From 3963425006ea738c93ca30b50cc0332dd522f0d9 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 5 Sep 2012 11:42:20 +0000 Subject: Merging r50374 through r50412 from trunk into soc-2011-tomato --- extern/bullet2/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'extern') diff --git a/extern/bullet2/CMakeLists.txt b/extern/bullet2/CMakeLists.txt index 4bf26ab3794..c57474f99f2 100644 --- a/extern/bullet2/CMakeLists.txt +++ b/extern/bullet2/CMakeLists.txt @@ -314,6 +314,7 @@ set(SRC src/BulletDynamics/Character/btKinematicCharacterController.h src/BulletSoftBody/btSoftBody.h + src/BulletSoftBody/btSoftBodyInternals.h src/BulletSoftBody/btSoftBodyData.h src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.h src/BulletSoftBody/btSoftBodyHelpers.h @@ -355,6 +356,7 @@ set(SRC src/btBulletCollisionCommon.h src/btBulletDynamicsCommon.h + src/Bullet-C-Api.h ) if(CMAKE_COMPILER_IS_GNUCXX) -- cgit v1.2.3 From de7a57a242c5305216e917cb9ab3b870dd10de59 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 13 Sep 2012 11:13:13 +0000 Subject: Merging r50522 through r50572 from trunk into soc-2011-tomato --- extern/libmv/third_party/ceres/SConscript | 5 +++++ .../libmv/third_party/ceres/internal/ceres/collections_port.h | 10 ++++++++++ 2 files changed, 15 insertions(+) (limited to 'extern') diff --git a/extern/libmv/third_party/ceres/SConscript b/extern/libmv/third_party/ceres/SConscript index 6b5f1b8d64d..c629fa00176 100644 --- a/extern/libmv/third_party/ceres/SConscript +++ b/extern/libmv/third_party/ceres/SConscript @@ -25,6 +25,11 @@ defs.append('CERES_RESTRICT_SCHUR_SPECIALIZATION') incs = '. ../../ ../../../Eigen3 ./include ./internal ../gflags' +# work around broken hashtable in 10.5 SDK +if env['OURPLATFORM'] == 'darwin' and env['WITH_BF_BOOST']: + incs += ' ' + env['BF_BOOST_INC'] + defs.append('CERES_HASH_BOOST') + if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'): if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): incs += ' ../msinttypes' diff --git a/extern/libmv/third_party/ceres/internal/ceres/collections_port.h b/extern/libmv/third_party/ceres/internal/ceres/collections_port.h index 6f8a830a85e..9dff0efe245 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/collections_port.h +++ b/extern/libmv/third_party/ceres/internal/ceres/collections_port.h @@ -33,6 +33,10 @@ #ifndef CERES_INTERNAL_COLLECTIONS_PORT_H_ #define CERES_INTERNAL_COLLECTIONS_PORT_H_ +#ifdef CERES_HASH_BOOST +#include +#include +#else #if defined(_MSC_VER) && _MSC_VER <= 1700 #include #include @@ -40,6 +44,8 @@ #include #include #endif +#endif + #include #include "ceres/integral_types.h" #include "ceres/internal/port.h" @@ -118,7 +124,11 @@ CERES_HASH_NAMESPACE_START // Hasher for STL pairs. Requires hashers for both members to be defined. template +#ifdef CERES_HASH_BOOST +struct hash { +#else struct hash > { +#endif size_t operator()(const pair& p) const { size_t h1 = hash()(p.first); size_t h2 = hash()(p.second); -- cgit v1.2.3 From 18326d852b5e82a1c5d1b9c0c45fad213a6d0d01 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 5 Nov 2012 19:42:27 +0000 Subject: Merging r50625 through r51896 from trunk into soc-2011-tomato Merging just in case we'll want to develop some experimental stuff --- extern/Eigen3/Eigen/Cholesky | 7 +- extern/Eigen3/Eigen/CholmodSupport | 45 + extern/Eigen3/Eigen/Core | 60 +- extern/Eigen3/Eigen/Eigen2Support | 46 +- extern/Eigen3/Eigen/Eigenvalues | 10 +- extern/Eigen3/Eigen/Geometry | 4 - extern/Eigen3/Eigen/Householder | 4 - extern/Eigen3/Eigen/IterativeLinearSolvers | 40 + extern/Eigen3/Eigen/Jacobi | 4 - extern/Eigen3/Eigen/LU | 7 +- extern/Eigen3/Eigen/LeastSquares | 4 - extern/Eigen3/Eigen/OrderingMethods | 23 + extern/Eigen3/Eigen/PaStiXSupport | 46 + extern/Eigen3/Eigen/PardisoSupport | 30 + extern/Eigen3/Eigen/QR | 8 +- extern/Eigen3/Eigen/SVD | 7 +- extern/Eigen3/Eigen/Sparse | 66 +- extern/Eigen3/Eigen/SparseCholesky | 30 + extern/Eigen3/Eigen/SparseCore | 66 ++ extern/Eigen3/Eigen/StdDeque | 21 +- extern/Eigen3/Eigen/StdList | 21 +- extern/Eigen3/Eigen/StdVector | 21 +- extern/Eigen3/Eigen/SuperLUSupport | 59 ++ extern/Eigen3/Eigen/UmfPackSupport | 36 + extern/Eigen3/Eigen/src/Cholesky/LDLT.h | 172 ++- extern/Eigen3/Eigen/src/Cholesky/LLT.h | 172 ++- extern/Eigen3/Eigen/src/Cholesky/LLT_MKL.h | 102 ++ .../Eigen/src/CholmodSupport/CholmodSupport.h | 579 ++++++++++ extern/Eigen3/Eigen/src/Core/Array.h | 24 +- extern/Eigen3/Eigen/src/Core/ArrayBase.h | 31 +- extern/Eigen3/Eigen/src/Core/ArrayWrapper.h | 53 +- extern/Eigen3/Eigen/src/Core/Assign.h | 132 ++- extern/Eigen3/Eigen/src/Core/Assign_MKL.h | 224 ++++ extern/Eigen3/Eigen/src/Core/BandMatrix.h | 26 +- extern/Eigen3/Eigen/src/Core/Block.h | 46 +- extern/Eigen3/Eigen/src/Core/BooleanRedux.h | 37 +- extern/Eigen3/Eigen/src/Core/CommaInitializer.h | 25 +- extern/Eigen3/Eigen/src/Core/CwiseBinaryOp.h | 29 +- extern/Eigen3/Eigen/src/Core/CwiseNullaryOp.h | 49 +- extern/Eigen3/Eigen/src/Core/CwiseUnaryOp.h | 27 +- extern/Eigen3/Eigen/src/Core/CwiseUnaryView.h | 27 +- extern/Eigen3/Eigen/src/Core/DenseBase.h | 28 +- extern/Eigen3/Eigen/src/Core/DenseCoeffsBase.h | 33 +- extern/Eigen3/Eigen/src/Core/DenseStorage.h | 47 +- extern/Eigen3/Eigen/src/Core/Diagonal.h | 59 +- extern/Eigen3/Eigen/src/Core/DiagonalMatrix.h | 31 +- extern/Eigen3/Eigen/src/Core/DiagonalProduct.h | 28 +- extern/Eigen3/Eigen/src/Core/Dot.h | 33 +- extern/Eigen3/Eigen/src/Core/EigenBase.h | 24 +- extern/Eigen3/Eigen/src/Core/Flagged.h | 25 +- extern/Eigen3/Eigen/src/Core/ForceAlignedAccess.h | 25 +- extern/Eigen3/Eigen/src/Core/Functors.h | 115 +- extern/Eigen3/Eigen/src/Core/Fuzzy.h | 29 +- extern/Eigen3/Eigen/src/Core/GeneralProduct.h | 613 +++++++++++ extern/Eigen3/Eigen/src/Core/GenericPacketMath.h | 27 +- extern/Eigen3/Eigen/src/Core/GlobalFunctions.h | 48 +- extern/Eigen3/Eigen/src/Core/IO.h | 27 +- extern/Eigen3/Eigen/src/Core/Map.h | 25 +- extern/Eigen3/Eigen/src/Core/MapBase.h | 23 +- extern/Eigen3/Eigen/src/Core/MathFunctions.h | 41 +- extern/Eigen3/Eigen/src/Core/Matrix.h | 44 +- extern/Eigen3/Eigen/src/Core/MatrixBase.h | 36 +- extern/Eigen3/Eigen/src/Core/NestByValue.h | 25 +- extern/Eigen3/Eigen/src/Core/NoAlias.h | 25 +- extern/Eigen3/Eigen/src/Core/NumTraits.h | 41 +- extern/Eigen3/Eigen/src/Core/PermutationMatrix.h | 31 +- extern/Eigen3/Eigen/src/Core/PlainObjectBase.h | 103 +- extern/Eigen3/Eigen/src/Core/Product.h | 643 +---------- extern/Eigen3/Eigen/src/Core/ProductBase.h | 32 +- extern/Eigen3/Eigen/src/Core/Random.h | 25 +- extern/Eigen3/Eigen/src/Core/Redux.h | 64 +- extern/Eigen3/Eigen/src/Core/Replicate.h | 33 +- extern/Eigen3/Eigen/src/Core/ReturnByValue.h | 25 +- extern/Eigen3/Eigen/src/Core/Reverse.h | 32 +- extern/Eigen3/Eigen/src/Core/Select.h | 46 +- extern/Eigen3/Eigen/src/Core/SelfAdjointView.h | 41 +- extern/Eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h | 35 +- extern/Eigen3/Eigen/src/Core/SolveTriangular.h | 47 +- extern/Eigen3/Eigen/src/Core/StableNorm.h | 31 +- extern/Eigen3/Eigen/src/Core/Stride.h | 25 +- extern/Eigen3/Eigen/src/Core/Swap.h | 36 +- extern/Eigen3/Eigen/src/Core/Transpose.h | 31 +- extern/Eigen3/Eigen/src/Core/Transpositions.h | 27 +- extern/Eigen3/Eigen/src/Core/TriangularMatrix.h | 57 +- extern/Eigen3/Eigen/src/Core/VectorBlock.h | 24 +- extern/Eigen3/Eigen/src/Core/VectorwiseOp.h | 109 +- extern/Eigen3/Eigen/src/Core/Visitor.h | 31 +- .../Eigen3/Eigen/src/Core/arch/AltiVec/Complex.h | 27 +- .../Eigen/src/Core/arch/AltiVec/PacketMath.h | 29 +- .../Eigen3/Eigen/src/Core/arch/Default/Settings.h | 21 +- extern/Eigen3/Eigen/src/Core/arch/NEON/Complex.h | 25 +- .../Eigen3/Eigen/src/Core/arch/NEON/PacketMath.h | 28 +- extern/Eigen3/Eigen/src/Core/arch/SSE/Complex.h | 31 +- .../Eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h | 29 +- extern/Eigen3/Eigen/src/Core/arch/SSE/PacketMath.h | 52 +- .../Eigen/src/Core/products/CoeffBasedProduct.h | 63 +- .../src/Core/products/GeneralBlockPanelKernel.h | 275 ++--- .../Eigen/src/Core/products/GeneralMatrixMatrix.h | 43 +- .../Core/products/GeneralMatrixMatrixTriangular.h | 41 +- .../products/GeneralMatrixMatrixTriangular_MKL.h | 146 +++ .../src/Core/products/GeneralMatrixMatrix_MKL.h | 118 +++ .../Eigen/src/Core/products/GeneralMatrixVector.h | 41 +- .../src/Core/products/GeneralMatrixVector_MKL.h | 131 +++ .../Eigen3/Eigen/src/Core/products/Parallelizer.h | 47 +- .../src/Core/products/SelfadjointMatrixMatrix.h | 29 +- .../Core/products/SelfadjointMatrixMatrix_MKL.h | 295 ++++++ .../src/Core/products/SelfadjointMatrixVector.h | 50 +- .../Core/products/SelfadjointMatrixVector_MKL.h | 114 ++ .../Eigen/src/Core/products/SelfadjointProduct.h | 31 +- .../src/Core/products/SelfadjointRank2Update.h | 29 +- .../src/Core/products/TriangularMatrixMatrix.h | 112 +- .../src/Core/products/TriangularMatrixMatrix_MKL.h | 309 ++++++ .../src/Core/products/TriangularMatrixVector.h | 101 +- .../src/Core/products/TriangularMatrixVector_MKL.h | 247 +++++ .../src/Core/products/TriangularSolverMatrix.h | 114 +- .../src/Core/products/TriangularSolverMatrix_MKL.h | 155 +++ .../src/Core/products/TriangularSolverVector.h | 25 +- extern/Eigen3/Eigen/src/Core/util/BlasUtil.h | 47 +- extern/Eigen3/Eigen/src/Core/util/Constants.h | 78 +- .../Eigen/src/Core/util/DisableStupidWarnings.h | 4 +- .../Eigen/src/Core/util/ForwardDeclarations.h | 27 +- extern/Eigen3/Eigen/src/Core/util/MKL_support.h | 109 ++ extern/Eigen3/Eigen/src/Core/util/Macros.h | 44 +- extern/Eigen3/Eigen/src/Core/util/Memory.h | 105 +- extern/Eigen3/Eigen/src/Core/util/Meta.h | 42 +- extern/Eigen3/Eigen/src/Core/util/NonMPL2.h | 3 + extern/Eigen3/Eigen/src/Core/util/StaticAssert.h | 45 +- extern/Eigen3/Eigen/src/Core/util/XprHelper.h | 60 +- extern/Eigen3/Eigen/src/Eigen2Support/Block.h | 25 +- extern/Eigen3/Eigen/src/Eigen2Support/Cwise.h | 25 +- .../Eigen/src/Eigen2Support/CwiseOperators.h | 25 +- .../Eigen/src/Eigen2Support/Geometry/AlignedBox.h | 33 +- .../Eigen3/Eigen/src/Eigen2Support/Geometry/All.h | 2 +- .../Eigen/src/Eigen2Support/Geometry/AngleAxis.h | 24 +- .../Eigen/src/Eigen2Support/Geometry/Hyperplane.h | 25 +- .../src/Eigen2Support/Geometry/ParametrizedLine.h | 24 +- .../Eigen/src/Eigen2Support/Geometry/Quaternion.h | 43 +- .../Eigen/src/Eigen2Support/Geometry/Rotation2D.h | 24 +- .../src/Eigen2Support/Geometry/RotationBase.h | 31 +- .../Eigen/src/Eigen2Support/Geometry/Scaling.h | 24 +- .../Eigen/src/Eigen2Support/Geometry/Transform.h | 24 +- .../Eigen/src/Eigen2Support/Geometry/Translation.h | 24 +- extern/Eigen3/Eigen/src/Eigen2Support/LU.h | 25 +- extern/Eigen3/Eigen/src/Eigen2Support/Lazy.h | 25 +- .../Eigen3/Eigen/src/Eigen2Support/LeastSquares.h | 24 +- extern/Eigen3/Eigen/src/Eigen2Support/Macros.h | 21 +- .../Eigen3/Eigen/src/Eigen2Support/MathFunctions.h | 25 +- extern/Eigen3/Eigen/src/Eigen2Support/Memory.h | 25 +- extern/Eigen3/Eigen/src/Eigen2Support/Meta.h | 25 +- extern/Eigen3/Eigen/src/Eigen2Support/Minor.h | 25 +- extern/Eigen3/Eigen/src/Eigen2Support/QR.h | 24 +- extern/Eigen3/Eigen/src/Eigen2Support/SVD.h | 27 +- .../Eigen/src/Eigen2Support/TriangularSolver.h | 25 +- .../Eigen3/Eigen/src/Eigen2Support/VectorBlock.h | 25 +- .../Eigen/src/Eigenvalues/ComplexEigenSolver.h | 25 +- extern/Eigen3/Eigen/src/Eigenvalues/ComplexSchur.h | 72 +- .../Eigen/src/Eigenvalues/ComplexSchur_MKL.h | 94 ++ extern/Eigen3/Eigen/src/Eigenvalues/EigenSolver.h | 32 +- .../Eigen/src/Eigenvalues/EigenvaluesCommon.h | 31 - .../GeneralizedSelfAdjointEigenSolver.h | 26 +- .../src/Eigenvalues/HessenbergDecomposition.h | 27 +- .../Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h | 25 +- extern/Eigen3/Eigen/src/Eigenvalues/RealSchur.h | 92 +- .../Eigen3/Eigen/src/Eigenvalues/RealSchur_MKL.h | 83 ++ .../Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h | 327 +++++- .../src/Eigenvalues/SelfAdjointEigenSolver_MKL.h | 92 ++ .../Eigen/src/Eigenvalues/Tridiagonalization.h | 33 +- extern/Eigen3/Eigen/src/Geometry/AlignedBox.h | 67 +- extern/Eigen3/Eigen/src/Geometry/AngleAxis.h | 27 +- extern/Eigen3/Eigen/src/Geometry/EulerAngles.h | 24 +- extern/Eigen3/Eigen/src/Geometry/Homogeneous.h | 39 +- extern/Eigen3/Eigen/src/Geometry/Hyperplane.h | 25 +- extern/Eigen3/Eigen/src/Geometry/OrthoMethods.h | 39 +- .../Eigen3/Eigen/src/Geometry/ParametrizedLine.h | 67 +- extern/Eigen3/Eigen/src/Geometry/Quaternion.h | 77 +- extern/Eigen3/Eigen/src/Geometry/Rotation2D.h | 27 +- extern/Eigen3/Eigen/src/Geometry/RotationBase.h | 37 +- extern/Eigen3/Eigen/src/Geometry/Scaling.h | 40 +- extern/Eigen3/Eigen/src/Geometry/Transform.h | 115 +- extern/Eigen3/Eigen/src/Geometry/Translation.h | 31 +- extern/Eigen3/Eigen/src/Geometry/Umeyama.h | 25 +- .../Eigen3/Eigen/src/Geometry/arch/Geometry_SSE.h | 31 +- .../Eigen/src/Householder/BlockHouseholder.h | 27 +- extern/Eigen3/Eigen/src/Householder/Householder.h | 73 +- .../Eigen/src/Householder/HouseholderSequence.h | 74 +- .../IterativeLinearSolvers/BasicPreconditioners.h | 149 +++ .../Eigen/src/IterativeLinearSolvers/BiCGSTAB.h | 254 +++++ .../src/IterativeLinearSolvers/ConjugateGradient.h | 251 +++++ .../src/IterativeLinearSolvers/IncompleteLUT.h | 466 ++++++++ .../IterativeLinearSolvers/IterativeSolverBase.h | 254 +++++ extern/Eigen3/Eigen/src/Jacobi/Jacobi.h | 32 +- extern/Eigen3/Eigen/src/LU/Determinant.h | 25 +- extern/Eigen3/Eigen/src/LU/FullPivLU.h | 26 +- extern/Eigen3/Eigen/src/LU/Inverse.h | 27 +- extern/Eigen3/Eigen/src/LU/PartialPivLU.h | 25 +- extern/Eigen3/Eigen/src/LU/PartialPivLU_MKL.h | 85 ++ extern/Eigen3/Eigen/src/LU/arch/Inverse_SSE.h | 27 +- extern/Eigen3/Eigen/src/OrderingMethods/Amd.h | 439 ++++++++ .../Eigen3/Eigen/src/PaStiXSupport/PaStiXSupport.h | 742 +++++++++++++ .../Eigen/src/PardisoSupport/PardisoSupport.h | 614 +++++++++++ extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR.h | 24 +- .../Eigen3/Eigen/src/QR/ColPivHouseholderQR_MKL.h | 98 ++ extern/Eigen3/Eigen/src/QR/FullPivHouseholderQR.h | 122 ++- extern/Eigen3/Eigen/src/QR/HouseholderQR.h | 24 +- extern/Eigen3/Eigen/src/QR/HouseholderQR_MKL.h | 69 ++ extern/Eigen3/Eigen/src/SVD/JacobiSVD.h | 294 ++++-- extern/Eigen3/Eigen/src/SVD/JacobiSVD_MKL.h | 92 ++ .../Eigen3/Eigen/src/SVD/UpperBidiagonalization.h | 25 +- extern/Eigen3/Eigen/src/Sparse/AmbiVector.h | 379 ------- extern/Eigen3/Eigen/src/Sparse/CompressedStorage.h | 239 ----- extern/Eigen3/Eigen/src/Sparse/CoreIterators.h | 71 -- .../Eigen3/Eigen/src/Sparse/DynamicSparseMatrix.h | 346 ------ .../Eigen3/Eigen/src/Sparse/MappedSparseMatrix.h | 165 --- extern/Eigen3/Eigen/src/Sparse/SparseAssign.h | 0 extern/Eigen3/Eigen/src/Sparse/SparseBlock.h | 465 -------- .../Eigen3/Eigen/src/Sparse/SparseCwiseBinaryOp.h | 375 ------- .../Eigen3/Eigen/src/Sparse/SparseCwiseUnaryOp.h | 146 --- .../Eigen3/Eigen/src/Sparse/SparseDenseProduct.h | 231 ---- .../Eigen/src/Sparse/SparseDiagonalProduct.h | 195 ---- extern/Eigen3/Eigen/src/Sparse/SparseDot.h | 97 -- extern/Eigen3/Eigen/src/Sparse/SparseFuzzy.h | 41 - extern/Eigen3/Eigen/src/Sparse/SparseMatrix.h | 651 ------------ extern/Eigen3/Eigen/src/Sparse/SparseMatrixBase.h | 706 ------------- extern/Eigen3/Eigen/src/Sparse/SparseProduct.h | 141 --- extern/Eigen3/Eigen/src/Sparse/SparseRedux.h | 56 - .../Eigen/src/Sparse/SparseSelfAdjointView.h | 454 -------- .../Eigen3/Eigen/src/Sparse/SparseSparseProduct.h | 401 ------- extern/Eigen3/Eigen/src/Sparse/SparseTranspose.h | 68 -- .../Eigen3/Eigen/src/Sparse/SparseTriangularView.h | 100 -- extern/Eigen3/Eigen/src/Sparse/SparseUtil.h | 130 --- extern/Eigen3/Eigen/src/Sparse/SparseVector.h | 431 -------- extern/Eigen3/Eigen/src/Sparse/SparseView.h | 109 -- extern/Eigen3/Eigen/src/Sparse/TriangularSolver.h | 339 ------ .../Eigen/src/SparseCholesky/SimplicialCholesky.h | 873 +++++++++++++++ extern/Eigen3/Eigen/src/SparseCore/AmbiVector.h | 371 +++++++ .../Eigen/src/SparseCore/CompressedStorage.h | 233 ++++ .../SparseCore/ConservativeSparseSparseProduct.h | 245 +++++ extern/Eigen3/Eigen/src/SparseCore/CoreIterators.h | 61 ++ .../Eigen/src/SparseCore/MappedSparseMatrix.h | 179 ++++ extern/Eigen3/Eigen/src/SparseCore/SparseAssign.h | 0 extern/Eigen3/Eigen/src/SparseCore/SparseBlock.h | 387 +++++++ .../Eigen/src/SparseCore/SparseCwiseBinaryOp.h | 324 ++++++ .../Eigen/src/SparseCore/SparseCwiseUnaryOp.h | 163 +++ .../Eigen/src/SparseCore/SparseDenseProduct.h | 300 ++++++ .../Eigen/src/SparseCore/SparseDiagonalProduct.h | 184 ++++ extern/Eigen3/Eigen/src/SparseCore/SparseDot.h | 94 ++ extern/Eigen3/Eigen/src/SparseCore/SparseFuzzy.h | 26 + extern/Eigen3/Eigen/src/SparseCore/SparseMatrix.h | 1116 ++++++++++++++++++++ .../Eigen3/Eigen/src/SparseCore/SparseMatrixBase.h | 458 ++++++++ .../Eigen/src/SparseCore/SparsePermutation.h | 148 +++ extern/Eigen3/Eigen/src/SparseCore/SparseProduct.h | 186 ++++ extern/Eigen3/Eigen/src/SparseCore/SparseRedux.h | 45 + .../Eigen/src/SparseCore/SparseSelfAdjointView.h | 480 +++++++++ .../SparseCore/SparseSparseProductWithPruning.h | 149 +++ .../Eigen3/Eigen/src/SparseCore/SparseTranspose.h | 61 ++ .../Eigen/src/SparseCore/SparseTriangularView.h | 164 +++ extern/Eigen3/Eigen/src/SparseCore/SparseUtil.h | 173 +++ extern/Eigen3/Eigen/src/SparseCore/SparseVector.h | 398 +++++++ extern/Eigen3/Eigen/src/SparseCore/SparseView.h | 98 ++ .../Eigen3/Eigen/src/SparseCore/TriangularSolver.h | 334 ++++++ extern/Eigen3/Eigen/src/StlSupport/StdDeque.h | 21 +- extern/Eigen3/Eigen/src/StlSupport/StdList.h | 21 +- extern/Eigen3/Eigen/src/StlSupport/StdVector.h | 21 +- extern/Eigen3/Eigen/src/StlSupport/details.h | 21 +- .../Eigen/src/SuperLUSupport/SuperLUSupport.h | 1025 ++++++++++++++++++ .../Eigen/src/UmfPackSupport/UmfPackSupport.h | 431 ++++++++ extern/Eigen3/Eigen/src/misc/Image.h | 25 +- extern/Eigen3/Eigen/src/misc/Kernel.h | 25 +- extern/Eigen3/Eigen/src/misc/Solve.h | 27 +- extern/Eigen3/Eigen/src/misc/SparseSolve.h | 111 ++ extern/Eigen3/Eigen/src/misc/blas.h | 658 ++++++++++++ .../Eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h | 56 + extern/Eigen3/Eigen/src/plugins/BlockMethods.h | 21 +- .../Eigen/src/plugins/CommonCwiseBinaryOps.h | 21 +- .../Eigen3/Eigen/src/plugins/CommonCwiseUnaryOps.h | 21 +- .../Eigen/src/plugins/MatrixCwiseBinaryOps.h | 42 +- .../Eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h | 21 +- extern/bullet2/patches/convex_hull.patch | 127 +++ extern/bullet2/readme.txt | 4 +- extern/bullet2/src/Bullet-C-Api.h | 10 + .../src/BulletDynamics/Dynamics/Bullet-C-API.cpp | 59 +- .../src/LinearMath/btConvexHullComputer.cpp | 2 + .../bullet2/src/LinearMath/btConvexHullComputer.h | 1 + extern/carve/CMakeLists.txt | 2 +- extern/libmv/CMakeLists.txt | 19 +- extern/libmv/bundle.sh | 6 +- extern/libmv/libmv-capi.cpp | 14 +- extern/libmv/libmv-capi.h | 17 +- .../libmv/libmv/multiview/euclidean_resection.cc | 46 +- extern/libmv/libmv/multiview/euclidean_resection.h | 12 +- extern/libmv/libmv/multiview/fundamental.cc | 4 +- extern/libmv/libmv/multiview/homography.cc | 2 +- extern/libmv/libmv/numeric/levenberg_marquardt.h | 10 +- extern/libmv/libmv/simple_pipeline/detect.cc | 2 +- .../simple_pipeline/initialize_reconstruction.cc | 1 + extern/libmv/libmv/simple_pipeline/intersect.cc | 1 + extern/libmv/libmv/simple_pipeline/pipeline.cc | 29 +- extern/libmv/libmv/simple_pipeline/pipeline.h | 12 +- .../libmv/libmv/simple_pipeline/reconstruction.h | 11 + extern/libmv/libmv/simple_pipeline/resect.cc | 21 +- extern/libmv/libmv/simple_pipeline/resect.h | 6 +- extern/libmv/libmv/tracking/track_region.cc | 213 +++- extern/libmv/libmv/tracking/track_region.h | 6 + extern/libmv/third_party/ceres/CMakeLists.txt | 50 +- extern/libmv/third_party/ceres/ChangeLog | 608 +++++++---- extern/libmv/third_party/ceres/SConscript | 6 +- extern/libmv/third_party/ceres/bundle.sh | 57 +- extern/libmv/third_party/ceres/files.txt | 22 +- .../ceres/include/ceres/autodiff_cost_function.h | 4 +- .../ceres/include/ceres/cost_function.h | 2 +- .../third_party/ceres/include/ceres/crs_matrix.h | 65 ++ .../third_party/ceres/include/ceres/fpclassify.h | 88 ++ .../ceres/include/ceres/internal/fixed_array.h | 3 +- .../ceres/include/ceres/internal/macros.h | 31 +- .../include/ceres/internal/manual_constructor.h | 71 +- .../ceres/include/ceres/internal/port.h | 6 + .../ceres/include/ceres/iteration_callback.h | 36 +- extern/libmv/third_party/ceres/include/ceres/jet.h | 163 +-- .../ceres/include/ceres/loss_function.h | 79 +- .../include/ceres/numeric_diff_cost_function.h | 6 +- .../third_party/ceres/include/ceres/problem.h | 6 +- .../third_party/ceres/include/ceres/rotation.h | 62 +- .../libmv/third_party/ceres/include/ceres/solver.h | 229 +++- .../libmv/third_party/ceres/include/ceres/types.h | 68 +- .../ceres/internal/ceres/array_utils.cc | 67 ++ .../third_party/ceres/internal/ceres/array_utils.h | 65 ++ .../internal/ceres/block_evaluate_preparer.cc | 16 +- .../ceres/internal/ceres/block_evaluate_preparer.h | 16 +- .../internal/ceres/block_jacobi_preconditioner.cc | 9 +- .../ceres/internal/ceres/block_jacobian_writer.cc | 5 +- .../ceres/block_random_access_dense_matrix.cc | 2 +- .../ceres/block_random_access_dense_matrix.h | 2 +- .../internal/ceres/block_random_access_matrix.h | 2 +- .../ceres/block_random_access_sparse_matrix.cc | 6 +- .../ceres/block_random_access_sparse_matrix.h | 8 +- .../ceres/internal/ceres/block_sparse_matrix.cc | 8 +- .../ceres/internal/ceres/block_sparse_matrix.h | 8 +- .../ceres/internal/ceres/block_structure.cc | 2 +- .../internal/ceres/canonical_views_clustering.cc | 8 +- .../third_party/ceres/internal/ceres/cgnr_solver.h | 2 +- .../ceres/internal/ceres/collections_port.h | 50 +- .../ceres/compressed_row_jacobian_writer.cc | 18 +- .../internal/ceres/compressed_row_sparse_matrix.cc | 28 +- .../internal/ceres/compressed_row_sparse_matrix.h | 28 +- .../internal/ceres/conditioned_cost_function.cc | 4 +- .../internal/ceres/conjugate_gradients_solver.cc | 20 +- .../internal/ceres/conjugate_gradients_solver.h | 2 +- .../third_party/ceres/internal/ceres/corrector.cc | 2 +- .../third_party/ceres/internal/ceres/cxsparse.cc | 130 +++ .../third_party/ceres/internal/ceres/cxsparse.h | 90 ++ .../internal/ceres/dense_normal_cholesky_solver.cc | 86 ++ .../internal/ceres/dense_normal_cholesky_solver.h | 95 ++ .../ceres/internal/ceres/dense_qr_solver.cc | 4 +- .../ceres/internal/ceres/dense_qr_solver.h | 4 +- .../ceres/internal/ceres/dense_sparse_matrix.cc | 6 +- .../ceres/internal/ceres/dense_sparse_matrix.h | 4 +- .../ceres/internal/ceres/detect_structure.cc | 14 +- .../ceres/internal/ceres/detect_structure.h | 2 +- .../ceres/internal/ceres/dogleg_strategy.cc | 691 ++++++++++++ .../ceres/internal/ceres/dogleg_strategy.h | 163 +++ .../third_party/ceres/internal/ceres/evaluator.cc | 82 +- .../third_party/ceres/internal/ceres/evaluator.h | 31 + .../libmv/third_party/ceres/internal/ceres/file.cc | 5 +- .../ceres/generate_eliminator_specialization.py | 186 ++++ .../ceres/gradient_checking_cost_function.cc | 10 +- .../libmv/third_party/ceres/internal/ceres/graph.h | 2 +- .../internal/ceres/implicit_schur_complement.cc | 23 +- .../internal/ceres/implicit_schur_complement.h | 10 +- .../ceres/iterative_schur_complement_solver.cc | 11 +- .../ceres/internal/ceres/levenberg_marquardt.cc | 574 ---------- .../ceres/internal/ceres/levenberg_marquardt.h | 65 -- .../internal/ceres/levenberg_marquardt_strategy.cc | 144 +++ .../internal/ceres/levenberg_marquardt_strategy.h | 86 ++ .../ceres/linear_least_squares_problems.cc | 101 +- .../ceres/internal/ceres/linear_solver.cc | 30 +- .../ceres/internal/ceres/linear_solver.h | 26 +- .../ceres/internal/ceres/local_parameterization.cc | 5 +- .../ceres/internal/ceres/loss_function.cc | 64 ++ .../ceres/internal/ceres/matrix_proto.h | 2 +- .../third_party/ceres/internal/ceres/minimizer.h | 68 +- .../libmv/third_party/ceres/internal/ceres/mutex.h | 98 +- .../ceres/internal/ceres/normal_prior.cc | 3 +- .../ceres/internal/ceres/parameter_block.h | 19 +- .../internal/ceres/partitioned_matrix_view.cc | 2 +- .../ceres/internal/ceres/polynomial_solver.cc | 184 ++++ .../ceres/internal/ceres/polynomial_solver.h | 65 ++ .../ceres/internal/ceres/problem_impl.cc | 9 +- .../ceres/internal/ceres/problem_impl.h | 2 +- .../third_party/ceres/internal/ceres/program.cc | 77 +- .../third_party/ceres/internal/ceres/program.h | 21 +- .../ceres/internal/ceres/program_evaluator.h | 84 +- .../third_party/ceres/internal/ceres/random.h | 29 +- .../ceres/internal/ceres/residual_block.cc | 7 +- .../ceres/internal/ceres/residual_block_utils.cc | 41 +- .../ceres/internal/ceres/residual_block_utils.h | 9 - .../ceres/runtime_numeric_diff_cost_function.cc | 3 +- .../internal/ceres/schur_complement_solver.cc | 159 ++- .../ceres/internal/ceres/schur_complement_solver.h | 38 +- .../ceres/internal/ceres/schur_eliminator_impl.h | 38 +- .../ceres/internal/ceres/schur_ordering.cc | 18 +- .../third_party/ceres/internal/ceres/solver.cc | 52 +- .../ceres/internal/ceres/solver_impl.cc | 296 ++++-- .../third_party/ceres/internal/ceres/solver_impl.h | 14 +- .../ceres/internal/ceres/sparse_matrix.h | 2 +- .../ceres/sparse_normal_cholesky_solver.cc | 166 ++- .../internal/ceres/sparse_normal_cholesky_solver.h | 36 +- .../third_party/ceres/internal/ceres/split.cc | 1 + .../libmv/third_party/ceres/internal/ceres/split.h | 21 + .../ceres/internal/ceres/stringprintf.cc | 1 + .../ceres/internal/ceres/stringprintf.h | 14 +- .../ceres/internal/ceres/suitesparse.cc | 157 ++- .../third_party/ceres/internal/ceres/suitesparse.h | 82 +- .../ceres/internal/ceres/triplet_sparse_matrix.cc | 10 +- .../ceres/internal/ceres/triplet_sparse_matrix.h | 4 +- .../ceres/internal/ceres/trust_region_minimizer.cc | 550 ++++++++++ .../ceres/internal/ceres/trust_region_minimizer.h | 67 ++ .../ceres/internal/ceres/trust_region_strategy.cc | 27 + .../ceres/internal/ceres/trust_region_strategy.h | 148 +++ .../third_party/ceres/internal/ceres/types.cc | 35 +- .../third_party/ceres/internal/ceres/visibility.cc | 4 +- .../ceres/visibility_based_preconditioner.cc | 36 +- .../ceres/visibility_based_preconditioner.h | 14 +- .../ceres/patches/collections_port.h.mingw.patch | 12 +- .../third_party/ceres/patches/msvc_glog_fix.patch | 50 + .../third_party/ceres/patches/msvc_isfinite.patch | 15 - .../patches/no_previous_declaration_fix.patch | 199 ++++ extern/libmv/third_party/ceres/patches/series | 4 +- .../Recast/Source/RecastMeshDetail.cpp | 2 +- 428 files changed, 26950 insertions(+), 12959 deletions(-) create mode 100644 extern/Eigen3/Eigen/CholmodSupport create mode 100644 extern/Eigen3/Eigen/IterativeLinearSolvers create mode 100644 extern/Eigen3/Eigen/OrderingMethods create mode 100644 extern/Eigen3/Eigen/PaStiXSupport create mode 100644 extern/Eigen3/Eigen/PardisoSupport create mode 100644 extern/Eigen3/Eigen/SparseCholesky create mode 100644 extern/Eigen3/Eigen/SparseCore create mode 100644 extern/Eigen3/Eigen/SuperLUSupport create mode 100644 extern/Eigen3/Eigen/UmfPackSupport create mode 100644 extern/Eigen3/Eigen/src/Cholesky/LLT_MKL.h create mode 100644 extern/Eigen3/Eigen/src/CholmodSupport/CholmodSupport.h create mode 100644 extern/Eigen3/Eigen/src/Core/Assign_MKL.h create mode 100644 extern/Eigen3/Eigen/src/Core/GeneralProduct.h create mode 100644 extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h create mode 100644 extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h create mode 100644 extern/Eigen3/Eigen/src/Core/products/GeneralMatrixVector_MKL.h create mode 100644 extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h create mode 100644 extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h create mode 100644 extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h create mode 100644 extern/Eigen3/Eigen/src/Core/products/TriangularMatrixVector_MKL.h create mode 100644 extern/Eigen3/Eigen/src/Core/products/TriangularSolverMatrix_MKL.h create mode 100644 extern/Eigen3/Eigen/src/Core/util/MKL_support.h create mode 100644 extern/Eigen3/Eigen/src/Core/util/NonMPL2.h create mode 100644 extern/Eigen3/Eigen/src/Eigenvalues/ComplexSchur_MKL.h delete mode 100644 extern/Eigen3/Eigen/src/Eigenvalues/EigenvaluesCommon.h create mode 100644 extern/Eigen3/Eigen/src/Eigenvalues/RealSchur_MKL.h create mode 100644 extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_MKL.h create mode 100644 extern/Eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h create mode 100644 extern/Eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h create mode 100644 extern/Eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h create mode 100644 extern/Eigen3/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h create mode 100644 extern/Eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h create mode 100644 extern/Eigen3/Eigen/src/LU/PartialPivLU_MKL.h create mode 100644 extern/Eigen3/Eigen/src/OrderingMethods/Amd.h create mode 100644 extern/Eigen3/Eigen/src/PaStiXSupport/PaStiXSupport.h create mode 100644 extern/Eigen3/Eigen/src/PardisoSupport/PardisoSupport.h create mode 100644 extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR_MKL.h create mode 100644 extern/Eigen3/Eigen/src/QR/HouseholderQR_MKL.h create mode 100644 extern/Eigen3/Eigen/src/SVD/JacobiSVD_MKL.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/AmbiVector.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/CompressedStorage.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/CoreIterators.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/DynamicSparseMatrix.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/MappedSparseMatrix.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseAssign.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseBlock.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseCwiseBinaryOp.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseCwiseUnaryOp.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseDenseProduct.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseDiagonalProduct.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseDot.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseFuzzy.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseMatrix.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseMatrixBase.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseProduct.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseRedux.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseSelfAdjointView.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseSparseProduct.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseTranspose.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseTriangularView.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseUtil.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseVector.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/SparseView.h delete mode 100644 extern/Eigen3/Eigen/src/Sparse/TriangularSolver.h create mode 100644 extern/Eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/AmbiVector.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/CompressedStorage.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/CoreIterators.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/MappedSparseMatrix.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseAssign.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseBlock.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseCwiseUnaryOp.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseDenseProduct.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseDiagonalProduct.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseDot.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseFuzzy.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseMatrix.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseMatrixBase.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparsePermutation.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseProduct.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseRedux.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseSelfAdjointView.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseSparseProductWithPruning.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseTranspose.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseTriangularView.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseUtil.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseVector.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/SparseView.h create mode 100644 extern/Eigen3/Eigen/src/SparseCore/TriangularSolver.h create mode 100644 extern/Eigen3/Eigen/src/SuperLUSupport/SuperLUSupport.h create mode 100644 extern/Eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h create mode 100644 extern/Eigen3/Eigen/src/misc/SparseSolve.h create mode 100644 extern/Eigen3/Eigen/src/misc/blas.h create mode 100644 extern/bullet2/patches/convex_hull.patch create mode 100644 extern/libmv/third_party/ceres/include/ceres/crs_matrix.h create mode 100644 extern/libmv/third_party/ceres/include/ceres/fpclassify.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/array_utils.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/array_utils.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/cxsparse.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/generate_eliminator_specialization.py delete mode 100644 extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt.cc delete mode 100644 extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/split.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h create mode 100644 extern/libmv/third_party/ceres/patches/msvc_glog_fix.patch delete mode 100644 extern/libmv/third_party/ceres/patches/msvc_isfinite.patch create mode 100644 extern/libmv/third_party/ceres/patches/no_previous_declaration_fix.patch (limited to 'extern') diff --git a/extern/Eigen3/Eigen/Cholesky b/extern/Eigen3/Eigen/Cholesky index 53f7bf911a4..f727f5d89c0 100644 --- a/extern/Eigen3/Eigen/Cholesky +++ b/extern/Eigen3/Eigen/Cholesky @@ -5,8 +5,6 @@ #include "src/Core/util/DisableStupidWarnings.h" -namespace Eigen { - /** \defgroup Cholesky_Module Cholesky module * * @@ -24,8 +22,9 @@ namespace Eigen { #include "src/misc/Solve.h" #include "src/Cholesky/LLT.h" #include "src/Cholesky/LDLT.h" - -} // namespace Eigen +#ifdef EIGEN_USE_LAPACKE +#include "src/Cholesky/LLT_MKL.h" +#endif #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/extern/Eigen3/Eigen/CholmodSupport b/extern/Eigen3/Eigen/CholmodSupport new file mode 100644 index 00000000000..745b884e74d --- /dev/null +++ b/extern/Eigen3/Eigen/CholmodSupport @@ -0,0 +1,45 @@ +#ifndef EIGEN_CHOLMODSUPPORT_MODULE_H +#define EIGEN_CHOLMODSUPPORT_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +extern "C" { + #include +} + +/** \ingroup Support_modules + * \defgroup CholmodSupport_Module CholmodSupport module + * + * This module provides an interface to the Cholmod library which is part of the suitesparse package. + * It provides the two following main factorization classes: + * - class CholmodSupernodalLLT: a supernodal LLT Cholesky factorization. + * - class CholmodDecomposiiton: a general L(D)LT Cholesky factorization with automatic or explicit runtime selection of the underlying factorization method (supernodal or simplicial). + * + * For the sake of completeness, this module also propose the two following classes: + * - class CholmodSimplicialLLT + * - class CholmodSimplicialLDLT + * Note that these classes does not bring any particular advantage compared to the built-in + * SimplicialLLT and SimplicialLDLT factorization classes. + * + * \code + * #include + * \endcode + * + * In order to use this module, the cholmod headers must be accessible from the include paths, and your binary must be linked to the cholmod library and its dependencies. + * The dependencies depend on how cholmod has been compiled. + * For a cmake based project, you can use our FindCholmod.cmake module to help you in this task. + * + */ + +#include "src/misc/Solve.h" +#include "src/misc/SparseSolve.h" + +#include "src/CholmodSupport/CholmodSupport.h" + + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_CHOLMODSUPPORT_MODULE_H + diff --git a/extern/Eigen3/Eigen/Core b/extern/Eigen3/Eigen/Core index a5025e37ead..d4801702261 100644 --- a/extern/Eigen3/Eigen/Core +++ b/extern/Eigen3/Eigen/Core @@ -4,24 +4,9 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2007-2011 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CORE_H #define EIGEN_CORE_H @@ -34,6 +19,12 @@ // defined e.g. EIGEN_DONT_ALIGN) so it needs to be done before we do anything with vectorization. #include "src/Core/util/Macros.h" +#include + +// this include file manages BLAS and MKL related macros +// and inclusion of their respective header files +#include "src/Core/util/MKL_support.h" + // if alignment is disabled, then disable vectorization. Note: EIGEN_ALIGN is the proper check, it takes into // account both the user's will (EIGEN_DONT_ALIGN) and our own platform checks #if !EIGEN_ALIGN @@ -136,7 +127,7 @@ #endif // MSVC for windows mobile does not have the errno.h file -#if !(defined(_MSC_VER) && defined(_WIN32_WCE)) +#if !(defined(_MSC_VER) && defined(_WIN32_WCE)) && !defined(__ARMCC_VERSION) #define EIGEN_HAS_ERRNO #endif @@ -146,7 +137,6 @@ #include #include #include -#include #include #include #include @@ -175,9 +165,6 @@ #include #endif -// defined in bits/termios.h -#undef B0 - /** \brief Namespace containing all symbols from the %Eigen library. */ namespace Eigen { @@ -201,6 +188,8 @@ inline static const char *SimdInstructionSetsInUse(void) { #endif } +} // end namespace Eigen + #define STAGE10_FULL_EIGEN2_API 10 #define STAGE20_RESOLVE_API_CONFLICTS 20 #define STAGE30_FULL_EIGEN3_API 30 @@ -247,6 +236,10 @@ using std::ptrdiff_t; * \endcode */ +/** \defgroup Support_modules Support modules [category] + * Category of modules which add support for external libraries. + */ + #include "src/Core/util/Constants.h" #include "src/Core/util/ForwardDeclarations.h" #include "src/Core/util/Meta.h" @@ -318,15 +311,15 @@ using std::ptrdiff_t; #include "src/Core/CommaInitializer.h" #include "src/Core/Flagged.h" #include "src/Core/ProductBase.h" -#include "src/Core/Product.h" +#include "src/Core/GeneralProduct.h" #include "src/Core/TriangularMatrix.h" #include "src/Core/SelfAdjointView.h" -#include "src/Core/SolveTriangular.h" +#include "src/Core/products/GeneralBlockPanelKernel.h" #include "src/Core/products/Parallelizer.h" #include "src/Core/products/CoeffBasedProduct.h" -#include "src/Core/products/GeneralBlockPanelKernel.h" #include "src/Core/products/GeneralMatrixVector.h" #include "src/Core/products/GeneralMatrixMatrix.h" +#include "src/Core/SolveTriangular.h" #include "src/Core/products/GeneralMatrixMatrixTriangular.h" #include "src/Core/products/SelfadjointMatrixVector.h" #include "src/Core/products/SelfadjointMatrixMatrix.h" @@ -347,7 +340,20 @@ using std::ptrdiff_t; #include "src/Core/ArrayBase.h" #include "src/Core/ArrayWrapper.h" -} // namespace Eigen +#ifdef EIGEN_USE_BLAS +#include "src/Core/products/GeneralMatrixMatrix_MKL.h" +#include "src/Core/products/GeneralMatrixVector_MKL.h" +#include "src/Core/products/GeneralMatrixMatrixTriangular_MKL.h" +#include "src/Core/products/SelfadjointMatrixMatrix_MKL.h" +#include "src/Core/products/SelfadjointMatrixVector_MKL.h" +#include "src/Core/products/TriangularMatrixMatrix_MKL.h" +#include "src/Core/products/TriangularMatrixVector_MKL.h" +#include "src/Core/products/TriangularSolverMatrix_MKL.h" +#endif // EIGEN_USE_BLAS + +#ifdef EIGEN_USE_MKL_VML +#include "src/Core/Assign_MKL.h" +#endif #include "src/Core/GlobalFunctions.h" diff --git a/extern/Eigen3/Eigen/Eigen2Support b/extern/Eigen3/Eigen/Eigen2Support index d96592a8de9..36156d29a92 100644 --- a/extern/Eigen3/Eigen/Eigen2Support +++ b/extern/Eigen3/Eigen/Eigen2Support @@ -3,24 +3,9 @@ // // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN2SUPPORT_H #define EIGEN2SUPPORT_H @@ -31,9 +16,8 @@ #include "src/Core/util/DisableStupidWarnings.h" -namespace Eigen { - -/** \defgroup Eigen2Support_Module Eigen2 support module +/** \ingroup Support_modules + * \defgroup Eigen2Support_Module Eigen2 support module * This module provides a couple of deprecated functions improving the compatibility with Eigen2. * * To use it, define EIGEN2_SUPPORT before including any Eigen header @@ -56,13 +40,29 @@ namespace Eigen { #include "src/Eigen2Support/MathFunctions.h" -} // namespace Eigen - #include "src/Core/util/ReenableStupidWarnings.h" // Eigen2 used to include iostream #include +#define EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, SizeSuffix) \ +using Eigen::Matrix##SizeSuffix##TypeSuffix; \ +using Eigen::Vector##SizeSuffix##TypeSuffix; \ +using Eigen::RowVector##SizeSuffix##TypeSuffix; + +#define EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(TypeSuffix) \ +EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 2) \ +EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 3) \ +EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 4) \ +EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, X) \ + +#define EIGEN_USING_MATRIX_TYPEDEFS \ +EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(i) \ +EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(f) \ +EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(d) \ +EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(cf) \ +EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(cd) + #define USING_PART_OF_NAMESPACE_EIGEN \ EIGEN_USING_MATRIX_TYPEDEFS \ using Eigen::Matrix; \ diff --git a/extern/Eigen3/Eigen/Eigenvalues b/extern/Eigen3/Eigen/Eigenvalues index 250c0f46652..af99ccd1fab 100644 --- a/extern/Eigen3/Eigen/Eigenvalues +++ b/extern/Eigen3/Eigen/Eigenvalues @@ -9,8 +9,7 @@ #include "Jacobi" #include "Householder" #include "LU" - -namespace Eigen { +#include "Geometry" /** \defgroup Eigenvalues_Module Eigenvalues module * @@ -35,8 +34,11 @@ namespace Eigen { #include "src/Eigenvalues/ComplexSchur.h" #include "src/Eigenvalues/ComplexEigenSolver.h" #include "src/Eigenvalues/MatrixBaseEigenvalues.h" - -} // namespace Eigen +#ifdef EIGEN_USE_LAPACKE +#include "src/Eigenvalues/RealSchur_MKL.h" +#include "src/Eigenvalues/ComplexSchur_MKL.h" +#include "src/Eigenvalues/SelfAdjointEigenSolver_MKL.h" +#endif #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/extern/Eigen3/Eigen/Geometry b/extern/Eigen3/Eigen/Geometry index 78277c0c560..efd9d4504cb 100644 --- a/extern/Eigen3/Eigen/Geometry +++ b/extern/Eigen3/Eigen/Geometry @@ -13,8 +13,6 @@ #define M_PI 3.14159265358979323846 #endif -namespace Eigen { - /** \defgroup Geometry_Module Geometry module * * @@ -58,8 +56,6 @@ namespace Eigen { #include "src/Eigen2Support/Geometry/All.h" #endif -} // namespace Eigen - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_GEOMETRY_MODULE_H diff --git a/extern/Eigen3/Eigen/Householder b/extern/Eigen3/Eigen/Householder index 6b86cf65c55..6e348db5c43 100644 --- a/extern/Eigen3/Eigen/Householder +++ b/extern/Eigen3/Eigen/Householder @@ -5,8 +5,6 @@ #include "src/Core/util/DisableStupidWarnings.h" -namespace Eigen { - /** \defgroup Householder_Module Householder module * This module provides Householder transformations. * @@ -19,8 +17,6 @@ namespace Eigen { #include "src/Householder/HouseholderSequence.h" #include "src/Householder/BlockHouseholder.h" -} // namespace Eigen - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_HOUSEHOLDER_MODULE_H diff --git a/extern/Eigen3/Eigen/IterativeLinearSolvers b/extern/Eigen3/Eigen/IterativeLinearSolvers new file mode 100644 index 00000000000..315c2dd1ee7 --- /dev/null +++ b/extern/Eigen3/Eigen/IterativeLinearSolvers @@ -0,0 +1,40 @@ +#ifndef EIGEN_ITERATIVELINEARSOLVERS_MODULE_H +#define EIGEN_ITERATIVELINEARSOLVERS_MODULE_H + +#include "SparseCore" +#include "OrderingMethods" + +#include "src/Core/util/DisableStupidWarnings.h" + +/** \ingroup Sparse_modules + * \defgroup IterativeLinearSolvers_Module IterativeLinearSolvers module + * + * This module currently provides iterative methods to solve problems of the form \c A \c x = \c b, where \c A is a squared matrix, usually very large and sparse. + * Those solvers are accessible via the following classes: + * - ConjugateGradient for selfadjoint (hermitian) matrices, + * - BiCGSTAB for general square matrices. + * + * These iterative solvers are associated with some preconditioners: + * - IdentityPreconditioner - not really useful + * - DiagonalPreconditioner - also called JAcobi preconditioner, work very well on diagonal dominant matrices. + * - IncompleteILUT - incomplete LU factorization with dual thresholding + * + * Such problems can also be solved using the direct sparse decomposition modules: SparseCholesky, CholmodSupport, UmfPackSupport, SuperLUSupport. + * + * \code + * #include + * \endcode + */ + +#include "src/misc/Solve.h" +#include "src/misc/SparseSolve.h" + +#include "src/IterativeLinearSolvers/IterativeSolverBase.h" +#include "src/IterativeLinearSolvers/BasicPreconditioners.h" +#include "src/IterativeLinearSolvers/ConjugateGradient.h" +#include "src/IterativeLinearSolvers/BiCGSTAB.h" +#include "src/IterativeLinearSolvers/IncompleteLUT.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_ITERATIVELINEARSOLVERS_MODULE_H diff --git a/extern/Eigen3/Eigen/Jacobi b/extern/Eigen3/Eigen/Jacobi index afa67681379..ba8a4dc36a5 100644 --- a/extern/Eigen3/Eigen/Jacobi +++ b/extern/Eigen3/Eigen/Jacobi @@ -5,8 +5,6 @@ #include "src/Core/util/DisableStupidWarnings.h" -namespace Eigen { - /** \defgroup Jacobi_Module Jacobi module * This module provides Jacobi and Givens rotations. * @@ -21,8 +19,6 @@ namespace Eigen { #include "src/Jacobi/Jacobi.h" -} // namespace Eigen - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_JACOBI_MODULE_H diff --git a/extern/Eigen3/Eigen/LU b/extern/Eigen3/Eigen/LU index 226f88ca38a..db579550448 100644 --- a/extern/Eigen3/Eigen/LU +++ b/extern/Eigen3/Eigen/LU @@ -5,8 +5,6 @@ #include "src/Core/util/DisableStupidWarnings.h" -namespace Eigen { - /** \defgroup LU_Module LU module * This module includes %LU decomposition and related notions such as matrix inversion and determinant. * This module defines the following MatrixBase methods: @@ -23,6 +21,9 @@ namespace Eigen { #include "src/misc/Image.h" #include "src/LU/FullPivLU.h" #include "src/LU/PartialPivLU.h" +#ifdef EIGEN_USE_LAPACKE +#include "src/LU/PartialPivLU_MKL.h" +#endif #include "src/LU/Determinant.h" #include "src/LU/Inverse.h" @@ -34,8 +35,6 @@ namespace Eigen { #include "src/Eigen2Support/LU.h" #endif -} // namespace Eigen - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_LU_MODULE_H diff --git a/extern/Eigen3/Eigen/LeastSquares b/extern/Eigen3/Eigen/LeastSquares index 93a6302dcd9..35137c25db0 100644 --- a/extern/Eigen3/Eigen/LeastSquares +++ b/extern/Eigen3/Eigen/LeastSquares @@ -15,8 +15,6 @@ #include "Eigenvalues" #include "Geometry" -namespace Eigen { - /** \defgroup LeastSquares_Module LeastSquares module * This module provides linear regression and related features. * @@ -27,8 +25,6 @@ namespace Eigen { #include "src/Eigen2Support/LeastSquares.h" -} // namespace Eigen - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN2_SUPPORT diff --git a/extern/Eigen3/Eigen/OrderingMethods b/extern/Eigen3/Eigen/OrderingMethods new file mode 100644 index 00000000000..1e2d87452e5 --- /dev/null +++ b/extern/Eigen3/Eigen/OrderingMethods @@ -0,0 +1,23 @@ +#ifndef EIGEN_ORDERINGMETHODS_MODULE_H +#define EIGEN_ORDERINGMETHODS_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +/** \ingroup Sparse_modules + * \defgroup OrderingMethods_Module OrderingMethods module + * + * This module is currently for internal use only. + * + * + * \code + * #include + * \endcode + */ + +#include "src/OrderingMethods/Amd.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_ORDERINGMETHODS_MODULE_H diff --git a/extern/Eigen3/Eigen/PaStiXSupport b/extern/Eigen3/Eigen/PaStiXSupport new file mode 100644 index 00000000000..7c616ee5eac --- /dev/null +++ b/extern/Eigen3/Eigen/PaStiXSupport @@ -0,0 +1,46 @@ +#ifndef EIGEN_PASTIXSUPPORT_MODULE_H +#define EIGEN_PASTIXSUPPORT_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +#include +extern "C" { +#include +#include +} + +#ifdef complex +#undef complex +#endif + +/** \ingroup Support_modules + * \defgroup PaStiXSupport_Module PaStiXSupport module + * + * This module provides an interface to the PaSTiX library. + * PaSTiX is a general \b supernodal, \b parallel and \b opensource sparse solver. + * It provides the two following main factorization classes: + * - class PastixLLT : a supernodal, parallel LLt Cholesky factorization. + * - class PastixLDLT: a supernodal, parallel LDLt Cholesky factorization. + * - class PastixLU : a supernodal, parallel LU factorization (optimized for a symmetric pattern). + * + * \code + * #include + * \endcode + * + * In order to use this module, the PaSTiX headers must be accessible from the include paths, and your binary must be linked to the PaSTiX library and its dependencies. + * The dependencies depend on how PaSTiX has been compiled. + * For a cmake based project, you can use our FindPaSTiX.cmake module to help you in this task. + * + */ + +#include "src/misc/Solve.h" +#include "src/misc/SparseSolve.h" + +#include "src/PaStiXSupport/PaStiXSupport.h" + + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_PASTIXSUPPORT_MODULE_H diff --git a/extern/Eigen3/Eigen/PardisoSupport b/extern/Eigen3/Eigen/PardisoSupport new file mode 100644 index 00000000000..99330ce7a7d --- /dev/null +++ b/extern/Eigen3/Eigen/PardisoSupport @@ -0,0 +1,30 @@ +#ifndef EIGEN_PARDISOSUPPORT_MODULE_H +#define EIGEN_PARDISOSUPPORT_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +#include + +#include + +/** \ingroup Support_modules + * \defgroup PardisoSupport_Module PardisoSupport module + * + * This module brings support for the Intel(R) MKL PARDISO direct sparse solvers. + * + * \code + * #include + * \endcode + * + * In order to use this module, the MKL headers must be accessible from the include paths, and your binary must be linked to the MKL library and its dependencies. + * See this \ref TopicUsingIntelMKL "page" for more information on MKL-Eigen integration. + * + */ + +#include "src/PardisoSupport/PardisoSupport.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_PARDISOSUPPORT_MODULE_H diff --git a/extern/Eigen3/Eigen/QR b/extern/Eigen3/Eigen/QR index 97c1788ee30..ac5b0269354 100644 --- a/extern/Eigen3/Eigen/QR +++ b/extern/Eigen3/Eigen/QR @@ -9,8 +9,6 @@ #include "Jacobi" #include "Householder" -namespace Eigen { - /** \defgroup QR_Module QR module * * @@ -28,13 +26,15 @@ namespace Eigen { #include "src/QR/HouseholderQR.h" #include "src/QR/FullPivHouseholderQR.h" #include "src/QR/ColPivHouseholderQR.h" +#ifdef EIGEN_USE_LAPACKE +#include "src/QR/HouseholderQR_MKL.h" +#include "src/QR/ColPivHouseholderQR_MKL.h" +#endif #ifdef EIGEN2_SUPPORT #include "src/Eigen2Support/QR.h" #endif -} // namespace Eigen - #include "src/Core/util/ReenableStupidWarnings.h" #ifdef EIGEN2_SUPPORT diff --git a/extern/Eigen3/Eigen/SVD b/extern/Eigen3/Eigen/SVD index 7c987a9dd36..fd310017ad1 100644 --- a/extern/Eigen3/Eigen/SVD +++ b/extern/Eigen3/Eigen/SVD @@ -7,8 +7,6 @@ #include "src/Core/util/DisableStupidWarnings.h" -namespace Eigen { - /** \defgroup SVD_Module SVD module * * @@ -24,14 +22,15 @@ namespace Eigen { #include "src/misc/Solve.h" #include "src/SVD/JacobiSVD.h" +#if defined(EIGEN_USE_LAPACKE) && !defined(EIGEN_USE_LAPACKE_STRICT) +#include "src/SVD/JacobiSVD_MKL.h" +#endif #include "src/SVD/UpperBidiagonalization.h" #ifdef EIGEN2_SUPPORT #include "src/Eigen2Support/SVD.h" #endif -} // namespace Eigen - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_SVD_MODULE_H diff --git a/extern/Eigen3/Eigen/Sparse b/extern/Eigen3/Eigen/Sparse index 7425b3a412a..2d1757172eb 100644 --- a/extern/Eigen3/Eigen/Sparse +++ b/extern/Eigen3/Eigen/Sparse @@ -1,69 +1,23 @@ #ifndef EIGEN_SPARSE_MODULE_H #define EIGEN_SPARSE_MODULE_H -#include "Core" - -#include "src/Core/util/DisableStupidWarnings.h" - -#include -#include -#include -#include -#include - -#ifdef EIGEN2_SUPPORT -#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET -#endif - -#ifndef EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET -#error The sparse module API is not stable yet. To use it anyway, please define the EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET preprocessor token. -#endif - -namespace Eigen { - -/** \defgroup Sparse_Module Sparse module +/** \defgroup Sparse_modules Sparse modules * - * - * - * See the \ref TutorialSparse "Sparse tutorial" + * Meta-module including all related modules: + * - SparseCore + * - OrderingMethods + * - SparseCholesky + * - IterativeLinearSolvers * * \code * #include * \endcode */ -/** The type used to identify a general sparse storage. */ -struct Sparse {}; - -#include "src/Sparse/SparseUtil.h" -#include "src/Sparse/SparseMatrixBase.h" -#include "src/Sparse/CompressedStorage.h" -#include "src/Sparse/AmbiVector.h" -#include "src/Sparse/SparseMatrix.h" -#include "src/Sparse/DynamicSparseMatrix.h" -#include "src/Sparse/MappedSparseMatrix.h" -#include "src/Sparse/SparseVector.h" -#include "src/Sparse/CoreIterators.h" -#include "src/Sparse/SparseBlock.h" -#include "src/Sparse/SparseTranspose.h" -#include "src/Sparse/SparseCwiseUnaryOp.h" -#include "src/Sparse/SparseCwiseBinaryOp.h" -#include "src/Sparse/SparseDot.h" -#include "src/Sparse/SparseAssign.h" -#include "src/Sparse/SparseRedux.h" -#include "src/Sparse/SparseFuzzy.h" -#include "src/Sparse/SparseProduct.h" -#include "src/Sparse/SparseSparseProduct.h" -#include "src/Sparse/SparseDenseProduct.h" -#include "src/Sparse/SparseDiagonalProduct.h" -#include "src/Sparse/SparseTriangularView.h" -#include "src/Sparse/SparseSelfAdjointView.h" -#include "src/Sparse/TriangularSolver.h" -#include "src/Sparse/SparseView.h" - -} // namespace Eigen - -#include "src/Core/util/ReenableStupidWarnings.h" +#include "SparseCore" +#include "OrderingMethods" +#include "SparseCholesky" +#include "IterativeLinearSolvers" #endif // EIGEN_SPARSE_MODULE_H diff --git a/extern/Eigen3/Eigen/SparseCholesky b/extern/Eigen3/Eigen/SparseCholesky new file mode 100644 index 00000000000..5f82742f7d8 --- /dev/null +++ b/extern/Eigen3/Eigen/SparseCholesky @@ -0,0 +1,30 @@ +#ifndef EIGEN_SPARSECHOLESKY_MODULE_H +#define EIGEN_SPARSECHOLESKY_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +/** \ingroup Sparse_modules + * \defgroup SparseCholesky_Module SparseCholesky module + * + * This module currently provides two variants of the direct sparse Cholesky decomposition for selfadjoint (hermitian) matrices. + * Those decompositions are accessible via the following classes: + * - SimplicialLLt, + * - SimplicialLDLt + * + * Such problems can also be solved using the ConjugateGradient solver from the IterativeLinearSolvers module. + * + * \code + * #include + * \endcode + */ + +#include "src/misc/Solve.h" +#include "src/misc/SparseSolve.h" + +#include "src/SparseCholesky/SimplicialCholesky.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_SPARSECHOLESKY_MODULE_H diff --git a/extern/Eigen3/Eigen/SparseCore b/extern/Eigen3/Eigen/SparseCore new file mode 100644 index 00000000000..41d28c92824 --- /dev/null +++ b/extern/Eigen3/Eigen/SparseCore @@ -0,0 +1,66 @@ +#ifndef EIGEN_SPARSECORE_MODULE_H +#define EIGEN_SPARSECORE_MODULE_H + +#include "Core" + +#include "src/Core/util/DisableStupidWarnings.h" + +#include +#include +#include +#include +#include + +/** \ingroup Sparse_modules + * \defgroup SparseCore_Module SparseCore module + * + * This module provides a sparse matrix representation, and basic associatd matrix manipulations + * and operations. + * + * See the \ref TutorialSparse "Sparse tutorial" + * + * \code + * #include + * \endcode + * + * This module depends on: Core. + */ + +namespace Eigen { + +/** The type used to identify a general sparse storage. */ +struct Sparse {}; + +} + +#include "src/SparseCore/SparseUtil.h" +#include "src/SparseCore/SparseMatrixBase.h" +#include "src/SparseCore/CompressedStorage.h" +#include "src/SparseCore/AmbiVector.h" +#include "src/SparseCore/SparseMatrix.h" +#include "src/SparseCore/MappedSparseMatrix.h" +#include "src/SparseCore/SparseVector.h" +#include "src/SparseCore/CoreIterators.h" +#include "src/SparseCore/SparseBlock.h" +#include "src/SparseCore/SparseTranspose.h" +#include "src/SparseCore/SparseCwiseUnaryOp.h" +#include "src/SparseCore/SparseCwiseBinaryOp.h" +#include "src/SparseCore/SparseDot.h" +#include "src/SparseCore/SparsePermutation.h" +#include "src/SparseCore/SparseAssign.h" +#include "src/SparseCore/SparseRedux.h" +#include "src/SparseCore/SparseFuzzy.h" +#include "src/SparseCore/ConservativeSparseSparseProduct.h" +#include "src/SparseCore/SparseSparseProductWithPruning.h" +#include "src/SparseCore/SparseProduct.h" +#include "src/SparseCore/SparseDenseProduct.h" +#include "src/SparseCore/SparseDiagonalProduct.h" +#include "src/SparseCore/SparseTriangularView.h" +#include "src/SparseCore/SparseSelfAdjointView.h" +#include "src/SparseCore/TriangularSolver.h" +#include "src/SparseCore/SparseView.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_SPARSECORE_MODULE_H + diff --git a/extern/Eigen3/Eigen/StdDeque b/extern/Eigen3/Eigen/StdDeque index a4f96232d8c..f27234778f4 100644 --- a/extern/Eigen3/Eigen/StdDeque +++ b/extern/Eigen3/Eigen/StdDeque @@ -4,24 +4,9 @@ // Copyright (C) 2009 Gael Guennebaud // Copyright (C) 2009 Hauke Heibel // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_STDDEQUE_MODULE_H #define EIGEN_STDDEQUE_MODULE_H diff --git a/extern/Eigen3/Eigen/StdList b/extern/Eigen3/Eigen/StdList index d914ded4f93..225c1e18f8e 100644 --- a/extern/Eigen3/Eigen/StdList +++ b/extern/Eigen3/Eigen/StdList @@ -3,24 +3,9 @@ // // Copyright (C) 2009 Hauke Heibel // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_STDLIST_MODULE_H #define EIGEN_STDLIST_MODULE_H diff --git a/extern/Eigen3/Eigen/StdVector b/extern/Eigen3/Eigen/StdVector index 3d8995e5aae..6b22627f6f6 100644 --- a/extern/Eigen3/Eigen/StdVector +++ b/extern/Eigen3/Eigen/StdVector @@ -4,24 +4,9 @@ // Copyright (C) 2009 Gael Guennebaud // Copyright (C) 2009 Hauke Heibel // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_STDVECTOR_MODULE_H #define EIGEN_STDVECTOR_MODULE_H diff --git a/extern/Eigen3/Eigen/SuperLUSupport b/extern/Eigen3/Eigen/SuperLUSupport new file mode 100644 index 00000000000..575e14fbc29 --- /dev/null +++ b/extern/Eigen3/Eigen/SuperLUSupport @@ -0,0 +1,59 @@ +#ifndef EIGEN_SUPERLUSUPPORT_MODULE_H +#define EIGEN_SUPERLUSUPPORT_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +#ifdef EMPTY +#define EIGEN_EMPTY_WAS_ALREADY_DEFINED +#endif + +typedef int int_t; +#include +#include +#include + +// slu_util.h defines a preprocessor token named EMPTY which is really polluting, +// so we remove it in favor of a SUPERLU_EMPTY token. +// If EMPTY was already defined then we don't undef it. + +#if defined(EIGEN_EMPTY_WAS_ALREADY_DEFINED) +# undef EIGEN_EMPTY_WAS_ALREADY_DEFINED +#elif defined(EMPTY) +# undef EMPTY +#endif + +#define SUPERLU_EMPTY (-1) + +namespace Eigen { struct SluMatrix; } + +/** \ingroup Support_modules + * \defgroup SuperLUSupport_Module SuperLUSupport module + * + * This module provides an interface to the SuperLU library. + * It provides the following factorization class: + * - class SuperLU: a supernodal sequential LU factorization. + * - class SuperILU: a supernodal sequential incomplete LU factorization (to be used as a preconditioner for iterative methods). + * + * \warning When including this module, you have to use SUPERLU_EMPTY instead of EMPTY which is no longer defined because it is too polluting. + * + * \code + * #include + * \endcode + * + * In order to use this module, the superlu headers must be accessible from the include paths, and your binary must be linked to the superlu library and its dependencies. + * The dependencies depend on how superlu has been compiled. + * For a cmake based project, you can use our FindSuperLU.cmake module to help you in this task. + * + */ + +#include "src/misc/Solve.h" +#include "src/misc/SparseSolve.h" + +#include "src/SuperLUSupport/SuperLUSupport.h" + + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_SUPERLUSUPPORT_MODULE_H diff --git a/extern/Eigen3/Eigen/UmfPackSupport b/extern/Eigen3/Eigen/UmfPackSupport new file mode 100644 index 00000000000..984f64a8419 --- /dev/null +++ b/extern/Eigen3/Eigen/UmfPackSupport @@ -0,0 +1,36 @@ +#ifndef EIGEN_UMFPACKSUPPORT_MODULE_H +#define EIGEN_UMFPACKSUPPORT_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +extern "C" { +#include +} + +/** \ingroup Support_modules + * \defgroup UmfPackSupport_Module UmfPackSupport module + * + * This module provides an interface to the UmfPack library which is part of the suitesparse package. + * It provides the following factorization class: + * - class UmfPackLU: a multifrontal sequential LU factorization. + * + * \code + * #include + * \endcode + * + * In order to use this module, the umfpack headers must be accessible from the include paths, and your binary must be linked to the umfpack library and its dependencies. + * The dependencies depend on how umfpack has been compiled. + * For a cmake based project, you can use our FindUmfPack.cmake module to help you in this task. + * + */ + +#include "src/misc/Solve.h" +#include "src/misc/SparseSolve.h" + +#include "src/UmfPackSupport/UmfPackSupport.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_UMFPACKSUPPORT_MODULE_H diff --git a/extern/Eigen3/Eigen/src/Cholesky/LDLT.h b/extern/Eigen3/Eigen/src/Cholesky/LDLT.h index a19e947a4c6..68e54b1d4ad 100644 --- a/extern/Eigen3/Eigen/src/Cholesky/LDLT.h +++ b/extern/Eigen3/Eigen/src/Cholesky/LDLT.h @@ -1,43 +1,33 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2011 Gael Guennebaud // Copyright (C) 2009 Keir Mierle // Copyright (C) 2009 Benoit Jacob +// Copyright (C) 2011 Timothy E. Holy // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_LDLT_H #define EIGEN_LDLT_H +namespace Eigen { + namespace internal { template struct LDLT_Traits; } -/** \ingroup cholesky_Module +/** \ingroup Cholesky_Module * * \class LDLT * * \brief Robust Cholesky decomposition of a matrix with pivoting * * \param MatrixType the type of the matrix of which to compute the LDL^T Cholesky decomposition + * \param UpLo the triangular part that will be used for the decompositon: Lower (default) or Upper. + * The other triangular part won't be read. * * Perform a robust Cholesky decomposition of a positive semidefinite or negative semidefinite * matrix \f$ A \f$ such that \f$ A = P^TLDL^*P \f$, where P is a permutation matrix, L @@ -48,14 +38,10 @@ template struct LDLT_Traits; * on D also stabilizes the computation. * * Remember that Cholesky decompositions are not rank-revealing. Also, do not use a Cholesky - * decomposition to determine whether a system of equations has a solution. + * decomposition to determine whether a system of equations has a solution. * * \sa MatrixBase::ldlt(), class LLT */ - /* THIS PART OF THE DOX IS CURRENTLY DISABLED BECAUSE INACCURATE BECAUSE OF BUG IN THE DECOMPOSITION CODE - * Note that during the decomposition, only the upper triangular part of A is considered. Therefore, - * the strict lower part does not have to store correct values. - */ template class LDLT { public: @@ -98,6 +84,11 @@ template class LDLT m_isInitialized(false) {} + /** \brief Constructor with decomposition + * + * This calculates the decomposition for the input \a matrix. + * \sa LDLT(Index size) + */ LDLT(const MatrixType& matrix) : m_matrix(matrix.rows(), matrix.cols()), m_transpositions(matrix.rows()), @@ -107,6 +98,14 @@ template class LDLT compute(matrix); } + /** Clear any existing decomposition + * \sa rankUpdate(w,sigma) + */ + void setZero() + { + m_isInitialized = false; + } + /** \returns a view of the upper triangular matrix U */ inline typename Traits::MatrixU matrixU() const { @@ -130,14 +129,14 @@ template class LDLT } /** \returns the coefficients of the diagonal matrix D */ - inline Diagonal vectorD(void) const + inline Diagonal vectorD() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return m_matrix.diagonal(); } /** \returns true if the matrix is positive (semidefinite) */ - inline bool isPositive(void) const + inline bool isPositive() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return m_sign == 1; @@ -196,6 +195,9 @@ template class LDLT LDLT& compute(const MatrixType& matrix); + template + LDLT& rankUpdate(const MatrixBase& w,RealScalar alpha=1); + /** \returns the internal LDLT decomposition matrix * * TODO: document the storage layout @@ -211,6 +213,17 @@ template class LDLT inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was succesful, + * \c NumericalIssue if the matrix.appears to be negative. + */ + ComputationInfo info() const + { + eigen_assert(m_isInitialized && "LDLT is not initialized."); + return Success; + } + protected: /** \internal @@ -249,7 +262,7 @@ template<> struct ldlt_inplace return true; } - RealScalar cutoff = 0, biggest_in_corner; + RealScalar cutoff(0), biggest_in_corner; for (Index k = 0; k < size; ++k) { @@ -317,6 +330,61 @@ template<> struct ldlt_inplace return true; } + + // Reference for the algorithm: Davis and Hager, "Multiple Rank + // Modifications of a Sparse Cholesky Factorization" (Algorithm 1) + // Trivial rearrangements of their computations (Timothy E. Holy) + // allow their algorithm to work for rank-1 updates even if the + // original matrix is not of full rank. + // Here only rank-1 updates are implemented, to reduce the + // requirement for intermediate storage and improve accuracy + template + static bool updateInPlace(MatrixType& mat, MatrixBase& w, typename MatrixType::RealScalar sigma=1) + { + using internal::isfinite; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + + const Index size = mat.rows(); + eigen_assert(mat.cols() == size && w.size()==size); + + RealScalar alpha = 1; + + // Apply the update + for (Index j = 0; j < size; j++) + { + // Check for termination due to an original decomposition of low-rank + if (!(isfinite)(alpha)) + break; + + // Update the diagonal terms + RealScalar dj = real(mat.coeff(j,j)); + Scalar wj = w.coeff(j); + RealScalar swj2 = sigma*abs2(wj); + RealScalar gamma = dj*alpha + swj2; + + mat.coeffRef(j,j) += swj2/alpha; + alpha += swj2/dj; + + + // Update the terms of L + Index rs = size-j-1; + w.tail(rs) -= wj * mat.col(j).tail(rs); + if(gamma != 0) + mat.col(j).tail(rs) += (sigma*conj(wj)/gamma)*w.tail(rs); + } + return true; + } + + template + static bool update(MatrixType& mat, const TranspositionType& transpositions, Workspace& tmp, const WType& w, typename MatrixType::RealScalar sigma=1) + { + // Apply the permutation to the input w + tmp = transpositions * w; + + return ldlt_inplace::updateInPlace(mat,tmp,sigma); + } }; template<> struct ldlt_inplace @@ -327,22 +395,29 @@ template<> struct ldlt_inplace Transpose matt(mat); return ldlt_inplace::unblocked(matt, transpositions, temp, sign); } + + template + static EIGEN_STRONG_INLINE bool update(MatrixType& mat, TranspositionType& transpositions, Workspace& tmp, WType& w, typename MatrixType::RealScalar sigma=1) + { + Transpose matt(mat); + return ldlt_inplace::update(matt, transpositions, tmp, w.conjugate(), sigma); + } }; template struct LDLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - inline static MatrixL getL(const MatrixType& m) { return m; } - inline static MatrixU getU(const MatrixType& m) { return m.adjoint(); } + static inline MatrixL getL(const MatrixType& m) { return m; } + static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } }; template struct LDLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - inline static MatrixL getL(const MatrixType& m) { return m.adjoint(); } - inline static MatrixU getU(const MatrixType& m) { return m; } + static inline MatrixL getL(const MatrixType& m) { return m.adjoint(); } + static inline MatrixU getU(const MatrixType& m) { return m; } }; } // end namespace internal @@ -367,6 +442,37 @@ LDLT& LDLT::compute(const MatrixType& a) return *this; } +/** Update the LDLT decomposition: given A = L D L^T, efficiently compute the decomposition of A + sigma w w^T. + * \param w a vector to be incorporated into the decomposition. + * \param sigma a scalar, +1 for updates and -1 for "downdates," which correspond to removing previously-added column vectors. Optional; default value is +1. + * \sa setZero() + */ +template +template +LDLT& LDLT::rankUpdate(const MatrixBase& w,typename NumTraits::Real sigma) +{ + const Index size = w.rows(); + if (m_isInitialized) + { + eigen_assert(m_matrix.rows()==size); + } + else + { + m_matrix.resize(size,size); + m_matrix.setZero(); + m_transpositions.resize(size); + for (Index i = 0; i < size; i++) + m_transpositions.coeffRef(i) = i; + m_temporary.resize(size); + m_sign = sigma>=0 ? 1 : -1; + m_isInitialized = true; + } + + internal::ldlt_inplace::update(m_matrix, m_transpositions, m_temporary, w, sigma); + + return *this; +} + namespace internal { template struct solve_retval, Rhs> @@ -481,4 +587,6 @@ MatrixBase::ldlt() const return LDLT(derived()); } +} // end namespace Eigen + #endif // EIGEN_LDLT_H diff --git a/extern/Eigen3/Eigen/src/Cholesky/LLT.h b/extern/Eigen3/Eigen/src/Cholesky/LLT.h index 3bb76b5787f..41d14e532f1 100644 --- a/extern/Eigen3/Eigen/src/Cholesky/LLT.h +++ b/extern/Eigen3/Eigen/src/Cholesky/LLT.h @@ -3,39 +3,28 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_LLT_H #define EIGEN_LLT_H +namespace Eigen { + namespace internal{ template struct LLT_Traits; } -/** \ingroup cholesky_Module +/** \ingroup Cholesky_Module * * \class LLT * * \brief Standard Cholesky decomposition (LL^T) of a matrix and associated features * * \param MatrixType the type of the matrix of which we are computing the LL^T Cholesky decomposition + * \param UpLo the triangular part that will be used for the decompositon: Lower (default) or Upper. + * The other triangular part won't be read. * * This class performs a LL^T Cholesky decomposition of a symmetric, positive definite * matrix A such that A = LL^* = U^*U, where L is lower triangular. @@ -49,6 +38,9 @@ template struct LLT_Traits; * use LDLT instead for the semidefinite case. Also, do not use a Cholesky decomposition to determine whether a system of equations * has a solution. * + * Example: \include LLT_example.cpp + * Output: \verbinclude LLT_example.out + * * \sa MatrixBase::llt(), class LDLT */ /* HEY THIS DOX IS DISABLED BECAUSE THERE's A BUG EITHER HERE OR IN LDLT ABOUT THAT (OR BOTH) @@ -178,6 +170,9 @@ template class LLT inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } + template + LLT rankUpdate(const VectorType& vec, const RealScalar& sigma = 1); + protected: /** \internal * Used to compute and store L @@ -190,16 +185,85 @@ template class LLT namespace internal { -template struct llt_inplace; +template struct llt_inplace; + +template +static typename MatrixType::Index llt_rank_update_lower(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + typedef typename MatrixType::ColXpr ColXpr; + typedef typename internal::remove_all::type ColXprCleaned; + typedef typename ColXprCleaned::SegmentReturnType ColXprSegment; + typedef Matrix TempVectorType; + typedef typename TempVectorType::SegmentReturnType TempVecSegment; + + int n = mat.cols(); + eigen_assert(mat.rows()==n && vec.size()==n); + + TempVectorType temp; + + if(sigma>0) + { + // This version is based on Givens rotations. + // It is faster than the other one below, but only works for updates, + // i.e., for sigma > 0 + temp = sqrt(sigma) * vec; + + for(int i=0; i g; + g.makeGivens(mat(i,i), -temp(i), &mat(i,i)); + + int rs = n-i-1; + if(rs>0) + { + ColXprSegment x(mat.col(i).tail(rs)); + TempVecSegment y(temp.tail(rs)); + apply_rotation_in_the_plane(x, y, g); + } + } + } + else + { + temp = vec; + RealScalar beta = 1; + for(int j=0; j struct llt_inplace +template struct llt_inplace { + typedef typename NumTraits::Real RealScalar; template static typename MatrixType::Index unblocked(MatrixType& mat) { typedef typename MatrixType::Index Index; - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::RealScalar RealScalar; eigen_assert(mat.rows()==mat.cols()); const Index size = mat.rows(); @@ -254,21 +318,35 @@ template<> struct llt_inplace } return -1; } -}; -template<> struct llt_inplace + template + static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) + { + return Eigen::internal::llt_rank_update_lower(mat, vec, sigma); + } +}; + +template struct llt_inplace { + typedef typename NumTraits::Real RealScalar; + template static EIGEN_STRONG_INLINE typename MatrixType::Index unblocked(MatrixType& mat) { Transpose matt(mat); - return llt_inplace::unblocked(matt); + return llt_inplace::unblocked(matt); } template static EIGEN_STRONG_INLINE typename MatrixType::Index blocked(MatrixType& mat) { Transpose matt(mat); - return llt_inplace::blocked(matt); + return llt_inplace::blocked(matt); + } + template + static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) + { + Transpose matt(mat); + return llt_inplace::rankUpdate(matt, vec.conjugate(), sigma); } }; @@ -276,33 +354,35 @@ template struct LLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - inline static MatrixL getL(const MatrixType& m) { return m; } - inline static MatrixU getU(const MatrixType& m) { return m.adjoint(); } + static inline MatrixL getL(const MatrixType& m) { return m; } + static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } static bool inplace_decomposition(MatrixType& m) - { return llt_inplace::blocked(m)==-1; } + { return llt_inplace::blocked(m)==-1; } }; template struct LLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - inline static MatrixL getL(const MatrixType& m) { return m.adjoint(); } - inline static MatrixU getU(const MatrixType& m) { return m; } + static inline MatrixL getL(const MatrixType& m) { return m.adjoint(); } + static inline MatrixU getU(const MatrixType& m) { return m; } static bool inplace_decomposition(MatrixType& m) - { return llt_inplace::blocked(m)==-1; } + { return llt_inplace::blocked(m)==-1; } }; } // end namespace internal /** Computes / recomputes the Cholesky decomposition A = LL^* = U^*U of \a matrix - * * * \returns a reference to *this + * + * Example: \include TutorialLinAlgComputeTwice.cpp + * Output: \verbinclude TutorialLinAlgComputeTwice.out */ template LLT& LLT::compute(const MatrixType& a) { - assert(a.rows()==a.cols()); + eigen_assert(a.rows()==a.cols()); const Index size = a.rows(); m_matrix.resize(size, size); m_matrix = a; @@ -314,6 +394,26 @@ LLT& LLT::compute(const MatrixType& a) return *this; } +/** Performs a rank one update (or dowdate) of the current decomposition. + * If A = LL^* before the rank one update, + * then after it we have LL^* = A + sigma * v v^* where \a v must be a vector + * of same dimension. + */ +template +template +LLT<_MatrixType,_UpLo> LLT<_MatrixType,_UpLo>::rankUpdate(const VectorType& v, const RealScalar& sigma) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(VectorType); + eigen_assert(v.size()==m_matrix.cols()); + eigen_assert(m_isInitialized); + if(internal::llt_inplace::rankUpdate(m_matrix,v,sigma)>=0) + m_info = NumericalIssue; + else + m_info = Success; + + return *this; +} + namespace internal { template struct solve_retval, Rhs> @@ -383,4 +483,6 @@ SelfAdjointView::llt() const return LLT(m_matrix); } +} // end namespace Eigen + #endif // EIGEN_LLT_H diff --git a/extern/Eigen3/Eigen/src/Cholesky/LLT_MKL.h b/extern/Eigen3/Eigen/src/Cholesky/LLT_MKL.h new file mode 100644 index 00000000000..64daa445cf7 --- /dev/null +++ b/extern/Eigen3/Eigen/src/Cholesky/LLT_MKL.h @@ -0,0 +1,102 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * LLt decomposition based on LAPACKE_?potrf function. + ******************************************************************************** +*/ + +#ifndef EIGEN_LLT_MKL_H +#define EIGEN_LLT_MKL_H + +#include "Eigen/src/Core/util/MKL_support.h" +#include + +namespace Eigen { + +namespace internal { + +template struct mkl_llt; + +#define EIGEN_MKL_LLT(EIGTYPE, MKLTYPE, MKLPREFIX) \ +template<> struct mkl_llt \ +{ \ + template \ + static inline typename MatrixType::Index potrf(MatrixType& m, char uplo) \ + { \ + lapack_int matrix_order; \ + lapack_int size, lda, info, StorageOrder; \ + EIGTYPE* a; \ + eigen_assert(m.rows()==m.cols()); \ + /* Set up parameters for ?potrf */ \ + size = m.rows(); \ + StorageOrder = MatrixType::Flags&RowMajorBit?RowMajor:ColMajor; \ + matrix_order = StorageOrder==RowMajor ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; \ + a = &(m.coeffRef(0,0)); \ + lda = m.outerStride(); \ +\ + info = LAPACKE_##MKLPREFIX##potrf( matrix_order, uplo, size, (MKLTYPE*)a, lda ); \ + info = (info==0) ? Success : NumericalIssue; \ + return info; \ + } \ +}; \ +template<> struct llt_inplace \ +{ \ + template \ + static typename MatrixType::Index blocked(MatrixType& m) \ + { \ + return mkl_llt::potrf(m, 'L'); \ + } \ + template \ + static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ + { return Eigen::internal::llt_rank_update_lower(mat, vec, sigma); } \ +}; \ +template<> struct llt_inplace \ +{ \ + template \ + static typename MatrixType::Index blocked(MatrixType& m) \ + { \ + return mkl_llt::potrf(m, 'U'); \ + } \ + template \ + static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ + { \ + Transpose matt(mat); \ + return llt_inplace::rankUpdate(matt, vec.conjugate(), sigma); \ + } \ +}; + +EIGEN_MKL_LLT(double, double, d) +EIGEN_MKL_LLT(float, float, s) +EIGEN_MKL_LLT(dcomplex, MKL_Complex16, z) +EIGEN_MKL_LLT(scomplex, MKL_Complex8, c) + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_LLT_MKL_H diff --git a/extern/Eigen3/Eigen/src/CholmodSupport/CholmodSupport.h b/extern/Eigen3/Eigen/src/CholmodSupport/CholmodSupport.h new file mode 100644 index 00000000000..37f142150ff --- /dev/null +++ b/extern/Eigen3/Eigen/src/CholmodSupport/CholmodSupport.h @@ -0,0 +1,579 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CHOLMODSUPPORT_H +#define EIGEN_CHOLMODSUPPORT_H + +namespace Eigen { + +namespace internal { + +template +void cholmod_configure_matrix(CholmodType& mat) +{ + if (internal::is_same::value) + { + mat.xtype = CHOLMOD_REAL; + mat.dtype = CHOLMOD_SINGLE; + } + else if (internal::is_same::value) + { + mat.xtype = CHOLMOD_REAL; + mat.dtype = CHOLMOD_DOUBLE; + } + else if (internal::is_same >::value) + { + mat.xtype = CHOLMOD_COMPLEX; + mat.dtype = CHOLMOD_SINGLE; + } + else if (internal::is_same >::value) + { + mat.xtype = CHOLMOD_COMPLEX; + mat.dtype = CHOLMOD_DOUBLE; + } + else + { + eigen_assert(false && "Scalar type not supported by CHOLMOD"); + } +} + +} // namespace internal + +/** Wraps the Eigen sparse matrix \a mat into a Cholmod sparse matrix object. + * Note that the data are shared. + */ +template +cholmod_sparse viewAsCholmod(SparseMatrix<_Scalar,_Options,_Index>& mat) +{ + typedef SparseMatrix<_Scalar,_Options,_Index> MatrixType; + cholmod_sparse res; + res.nzmax = mat.nonZeros(); + res.nrow = mat.rows();; + res.ncol = mat.cols(); + res.p = mat.outerIndexPtr(); + res.i = mat.innerIndexPtr(); + res.x = mat.valuePtr(); + res.sorted = 1; + if(mat.isCompressed()) + { + res.packed = 1; + } + else + { + res.packed = 0; + res.nz = mat.innerNonZeroPtr(); + } + + res.dtype = 0; + res.stype = -1; + + if (internal::is_same<_Index,int>::value) + { + res.itype = CHOLMOD_INT; + } + else + { + eigen_assert(false && "Index type different than int is not supported yet"); + } + + // setup res.xtype + internal::cholmod_configure_matrix<_Scalar>(res); + + res.stype = 0; + + return res; +} + +template +const cholmod_sparse viewAsCholmod(const SparseMatrix<_Scalar,_Options,_Index>& mat) +{ + cholmod_sparse res = viewAsCholmod(mat.const_cast_derived()); + return res; +} + +/** Returns a view of the Eigen sparse matrix \a mat as Cholmod sparse matrix. + * The data are not copied but shared. */ +template +cholmod_sparse viewAsCholmod(const SparseSelfAdjointView, UpLo>& mat) +{ + cholmod_sparse res = viewAsCholmod(mat.matrix().const_cast_derived()); + + if(UpLo==Upper) res.stype = 1; + if(UpLo==Lower) res.stype = -1; + + return res; +} + +/** Returns a view of the Eigen \b dense matrix \a mat as Cholmod dense matrix. + * The data are not copied but shared. */ +template +cholmod_dense viewAsCholmod(MatrixBase& mat) +{ + EIGEN_STATIC_ASSERT((internal::traits::Flags&RowMajorBit)==0,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); + typedef typename Derived::Scalar Scalar; + + cholmod_dense res; + res.nrow = mat.rows(); + res.ncol = mat.cols(); + res.nzmax = res.nrow * res.ncol; + res.d = Derived::IsVectorAtCompileTime ? mat.derived().size() : mat.derived().outerStride(); + res.x = mat.derived().data(); + res.z = 0; + + internal::cholmod_configure_matrix(res); + + return res; +} + +/** Returns a view of the Cholmod sparse matrix \a cm as an Eigen sparse matrix. + * The data are not copied but shared. */ +template +MappedSparseMatrix viewAsEigen(cholmod_sparse& cm) +{ + return MappedSparseMatrix + (cm.nrow, cm.ncol, reinterpret_cast(cm.p)[cm.ncol], + reinterpret_cast(cm.p), reinterpret_cast(cm.i),reinterpret_cast(cm.x) ); +} + +enum CholmodMode { + CholmodAuto, CholmodSimplicialLLt, CholmodSupernodalLLt, CholmodLDLt +}; + + +/** \ingroup CholmodSupport_Module + * \class CholmodBase + * \brief The base class for the direct Cholesky factorization of Cholmod + * \sa class CholmodSupernodalLLT, class CholmodSimplicialLDLT, class CholmodSimplicialLLT + */ +template +class CholmodBase : internal::noncopyable +{ + public: + typedef _MatrixType MatrixType; + enum { UpLo = _UpLo }; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef MatrixType CholMatrixType; + typedef typename MatrixType::Index Index; + + public: + + CholmodBase() + : m_cholmodFactor(0), m_info(Success), m_isInitialized(false) + { + cholmod_start(&m_cholmod); + } + + CholmodBase(const MatrixType& matrix) + : m_cholmodFactor(0), m_info(Success), m_isInitialized(false) + { + cholmod_start(&m_cholmod); + compute(matrix); + } + + ~CholmodBase() + { + if(m_cholmodFactor) + cholmod_free_factor(&m_cholmodFactor, &m_cholmod); + cholmod_finish(&m_cholmod); + } + + inline Index cols() const { return m_cholmodFactor->n; } + inline Index rows() const { return m_cholmodFactor->n; } + + Derived& derived() { return *static_cast(this); } + const Derived& derived() const { return *static_cast(this); } + + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was succesful, + * \c NumericalIssue if the matrix.appears to be negative. + */ + ComputationInfo info() const + { + eigen_assert(m_isInitialized && "Decomposition is not initialized."); + return m_info; + } + + /** Computes the sparse Cholesky decomposition of \a matrix */ + Derived& compute(const MatrixType& matrix) + { + analyzePattern(matrix); + factorize(matrix); + return derived(); + } + + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ + template + inline const internal::solve_retval + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "LLT is not initialized."); + eigen_assert(rows()==b.rows() + && "CholmodDecomposition::solve(): invalid number of rows of the right hand side matrix b"); + return internal::solve_retval(*this, b.derived()); + } + + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ + template + inline const internal::sparse_solve_retval + solve(const SparseMatrixBase& b) const + { + eigen_assert(m_isInitialized && "LLT is not initialized."); + eigen_assert(rows()==b.rows() + && "CholmodDecomposition::solve(): invalid number of rows of the right hand side matrix b"); + return internal::sparse_solve_retval(*this, b.derived()); + } + + /** Performs a symbolic decomposition on the sparcity of \a matrix. + * + * This function is particularly useful when solving for several problems having the same structure. + * + * \sa factorize() + */ + void analyzePattern(const MatrixType& matrix) + { + if(m_cholmodFactor) + { + cholmod_free_factor(&m_cholmodFactor, &m_cholmod); + m_cholmodFactor = 0; + } + cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView()); + m_cholmodFactor = cholmod_analyze(&A, &m_cholmod); + + this->m_isInitialized = true; + this->m_info = Success; + m_analysisIsOk = true; + m_factorizationIsOk = false; + } + + /** Performs a numeric decomposition of \a matrix + * + * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. + * + * \sa analyzePattern() + */ + void factorize(const MatrixType& matrix) + { + eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); + cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView()); + cholmod_factorize(&A, m_cholmodFactor, &m_cholmod); + + this->m_info = Success; + m_factorizationIsOk = true; + } + + /** Returns a reference to the Cholmod's configuration structure to get a full control over the performed operations. + * See the Cholmod user guide for details. */ + cholmod_common& cholmod() { return m_cholmod; } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal */ + template + void _solve(const MatrixBase &b, MatrixBase &dest) const + { + eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); + const Index size = m_cholmodFactor->n; + eigen_assert(size==b.rows()); + + // note: cd stands for Cholmod Dense + cholmod_dense b_cd = viewAsCholmod(b.const_cast_derived()); + cholmod_dense* x_cd = cholmod_solve(CHOLMOD_A, m_cholmodFactor, &b_cd, &m_cholmod); + if(!x_cd) + { + this->m_info = NumericalIssue; + } + // TODO optimize this copy by swapping when possible (be carreful with alignment, etc.) + dest = Matrix::Map(reinterpret_cast(x_cd->x),b.rows(),b.cols()); + cholmod_free_dense(&x_cd, &m_cholmod); + } + + /** \internal */ + template + void _solve(const SparseMatrix &b, SparseMatrix &dest) const + { + eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); + const Index size = m_cholmodFactor->n; + eigen_assert(size==b.rows()); + + // note: cs stands for Cholmod Sparse + cholmod_sparse b_cs = viewAsCholmod(b); + cholmod_sparse* x_cs = cholmod_spsolve(CHOLMOD_A, m_cholmodFactor, &b_cs, &m_cholmod); + if(!x_cs) + { + this->m_info = NumericalIssue; + } + // TODO optimize this copy by swapping when possible (be carreful with alignment, etc.) + dest = viewAsEigen(*x_cs); + cholmod_free_sparse(&x_cs, &m_cholmod); + } + #endif // EIGEN_PARSED_BY_DOXYGEN + + template + void dumpMemory(Stream& s) + {} + + protected: + mutable cholmod_common m_cholmod; + cholmod_factor* m_cholmodFactor; + mutable ComputationInfo m_info; + bool m_isInitialized; + int m_factorizationIsOk; + int m_analysisIsOk; +}; + +/** \ingroup CholmodSupport_Module + * \class CholmodSimplicialLLT + * \brief A simplicial direct Cholesky (LLT) factorization and solver based on Cholmod + * + * This class allows to solve for A.X = B sparse linear problems via a simplicial LL^T Cholesky factorization + * using the Cholmod library. + * This simplicial variant is equivalent to Eigen's built-in SimplicialLLT class. Thefore, it has little practical interest. + * The sparse matrix A must be selfajoint and positive definite. The vectors or matrices + * X and B can be either dense or sparse. + * + * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower + * or Upper. Default is Lower. + * + * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. + * + * \sa \ref TutorialSparseDirectSolvers, class CholmodSupernodalLLT, class SimplicialLLT + */ +template +class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT<_MatrixType, _UpLo> > +{ + typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT> Base; + using Base::m_cholmod; + + public: + + typedef _MatrixType MatrixType; + + CholmodSimplicialLLT() : Base() { init(); } + + CholmodSimplicialLLT(const MatrixType& matrix) : Base() + { + init(); + compute(matrix); + } + + ~CholmodSimplicialLLT() {} + protected: + void init() + { + m_cholmod.final_asis = 0; + m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; + m_cholmod.final_ll = 1; + } +}; + + +/** \ingroup CholmodSupport_Module + * \class CholmodSimplicialLDLT + * \brief A simplicial direct Cholesky (LDLT) factorization and solver based on Cholmod + * + * This class allows to solve for A.X = B sparse linear problems via a simplicial LDL^T Cholesky factorization + * using the Cholmod library. + * This simplicial variant is equivalent to Eigen's built-in SimplicialLDLT class. Thefore, it has little practical interest. + * The sparse matrix A must be selfajoint and positive definite. The vectors or matrices + * X and B can be either dense or sparse. + * + * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower + * or Upper. Default is Lower. + * + * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. + * + * \sa \ref TutorialSparseDirectSolvers, class CholmodSupernodalLLT, class SimplicialLDLT + */ +template +class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT<_MatrixType, _UpLo> > +{ + typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT> Base; + using Base::m_cholmod; + + public: + + typedef _MatrixType MatrixType; + + CholmodSimplicialLDLT() : Base() { init(); } + + CholmodSimplicialLDLT(const MatrixType& matrix) : Base() + { + init(); + compute(matrix); + } + + ~CholmodSimplicialLDLT() {} + protected: + void init() + { + m_cholmod.final_asis = 1; + m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; + } +}; + +/** \ingroup CholmodSupport_Module + * \class CholmodSupernodalLLT + * \brief A supernodal Cholesky (LLT) factorization and solver based on Cholmod + * + * This class allows to solve for A.X = B sparse linear problems via a supernodal LL^T Cholesky factorization + * using the Cholmod library. + * This supernodal variant performs best on dense enough problems, e.g., 3D FEM, or very high order 2D FEM. + * The sparse matrix A must be selfajoint and positive definite. The vectors or matrices + * X and B can be either dense or sparse. + * + * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower + * or Upper. Default is Lower. + * + * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. + * + * \sa \ref TutorialSparseDirectSolvers + */ +template +class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT<_MatrixType, _UpLo> > +{ + typedef CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT> Base; + using Base::m_cholmod; + + public: + + typedef _MatrixType MatrixType; + + CholmodSupernodalLLT() : Base() { init(); } + + CholmodSupernodalLLT(const MatrixType& matrix) : Base() + { + init(); + compute(matrix); + } + + ~CholmodSupernodalLLT() {} + protected: + void init() + { + m_cholmod.final_asis = 1; + m_cholmod.supernodal = CHOLMOD_SUPERNODAL; + } +}; + +/** \ingroup CholmodSupport_Module + * \class CholmodDecomposition + * \brief A general Cholesky factorization and solver based on Cholmod + * + * This class allows to solve for A.X = B sparse linear problems via a LL^T or LDL^T Cholesky factorization + * using the Cholmod library. The sparse matrix A must be selfajoint and positive definite. The vectors or matrices + * X and B can be either dense or sparse. + * + * This variant permits to change the underlying Cholesky method at runtime. + * On the other hand, it does not provide access to the result of the factorization. + * The default is to let Cholmod automatically choose between a simplicial and supernodal factorization. + * + * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower + * or Upper. Default is Lower. + * + * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. + * + * \sa \ref TutorialSparseDirectSolvers + */ +template +class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecomposition<_MatrixType, _UpLo> > +{ + typedef CholmodBase<_MatrixType, _UpLo, CholmodDecomposition> Base; + using Base::m_cholmod; + + public: + + typedef _MatrixType MatrixType; + + CholmodDecomposition() : Base() { init(); } + + CholmodDecomposition(const MatrixType& matrix) : Base() + { + init(); + compute(matrix); + } + + ~CholmodDecomposition() {} + + void setMode(CholmodMode mode) + { + switch(mode) + { + case CholmodAuto: + m_cholmod.final_asis = 1; + m_cholmod.supernodal = CHOLMOD_AUTO; + break; + case CholmodSimplicialLLt: + m_cholmod.final_asis = 0; + m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; + m_cholmod.final_ll = 1; + break; + case CholmodSupernodalLLt: + m_cholmod.final_asis = 1; + m_cholmod.supernodal = CHOLMOD_SUPERNODAL; + break; + case CholmodLDLt: + m_cholmod.final_asis = 1; + m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; + break; + default: + break; + } + } + protected: + void init() + { + m_cholmod.final_asis = 1; + m_cholmod.supernodal = CHOLMOD_AUTO; + } +}; + +namespace internal { + +template +struct solve_retval, Rhs> + : solve_retval_base, Rhs> +{ + typedef CholmodBase<_MatrixType,_UpLo,Derived> Dec; + EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec()._solve(rhs(),dst); + } +}; + +template +struct sparse_solve_retval, Rhs> + : sparse_solve_retval_base, Rhs> +{ + typedef CholmodBase<_MatrixType,_UpLo,Derived> Dec; + EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec()._solve(rhs(),dst); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_CHOLMODSUPPORT_H diff --git a/extern/Eigen3/Eigen/src/Core/Array.h b/extern/Eigen3/Eigen/src/Core/Array.h index a11fb1b53d5..aaa38997838 100644 --- a/extern/Eigen3/Eigen/src/Core/Array.h +++ b/extern/Eigen3/Eigen/src/Core/Array.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ARRAY_H #define EIGEN_ARRAY_H +namespace Eigen { + /** \class Array * \ingroup Core_Module * @@ -316,5 +303,6 @@ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(d) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cf) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cd) +} // end namespace Eigen #endif // EIGEN_ARRAY_H diff --git a/extern/Eigen3/Eigen/src/Core/ArrayBase.h b/extern/Eigen3/Eigen/src/Core/ArrayBase.h index 9399ac3d15c..004b117c933 100644 --- a/extern/Eigen3/Eigen/src/Core/ArrayBase.h +++ b/extern/Eigen3/Eigen/src/Core/ArrayBase.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ARRAYBASE_H #define EIGEN_ARRAYBASE_H +namespace Eigen { + template class MatrixWrapper; /** \class ArrayBase @@ -159,7 +146,7 @@ template class ArrayBase /** \returns an \link MatrixBase Matrix \endlink expression of this array * \sa MatrixBase::array() */ MatrixWrapper matrix() { return derived(); } - const MatrixWrapper matrix() const { return derived(); } + const MatrixWrapper matrix() const { return derived(); } // template // inline void evalTo(Dest& dst) const { dst = matrix(); } @@ -174,10 +161,10 @@ template class ArrayBase protected: // mixing arrays and matrices is not legal template Derived& operator+=(const MatrixBase& ) - {EIGEN_STATIC_ASSERT(sizeof(typename OtherDerived::Scalar)==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES);} + {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} // mixing arrays and matrices is not legal template Derived& operator-=(const MatrixBase& ) - {EIGEN_STATIC_ASSERT(sizeof(typename OtherDerived::Scalar)==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES);} + {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} }; /** replaces \c *this by \c *this - \a other. @@ -236,4 +223,6 @@ ArrayBase::operator/=(const ArrayBase& other) return derived(); } +} // end namespace Eigen + #endif // EIGEN_ARRAYBASE_H diff --git a/extern/Eigen3/Eigen/src/Core/ArrayWrapper.h b/extern/Eigen3/Eigen/src/Core/ArrayWrapper.h index 07f082e1edc..87af7fda937 100644 --- a/extern/Eigen3/Eigen/src/Core/ArrayWrapper.h +++ b/extern/Eigen3/Eigen/src/Core/ArrayWrapper.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ARRAYWRAPPER_H #define EIGEN_ARRAYWRAPPER_H +namespace Eigen { + /** \class ArrayWrapper * \ingroup Core_Module * @@ -61,7 +48,7 @@ class ArrayWrapper : public ArrayBase > typedef typename internal::nested::type NestedExpressionType; - inline ArrayWrapper(const ExpressionType& matrix) : m_expression(matrix) {} + inline ArrayWrapper(ExpressionType& matrix) : m_expression(matrix) {} inline Index rows() const { return m_expression.rows(); } inline Index cols() const { return m_expression.cols(); } @@ -71,7 +58,7 @@ class ArrayWrapper : public ArrayBase > inline ScalarWithConstIfNotLvalue* data() { return m_expression.data(); } inline const Scalar* data() const { return m_expression.data(); } - inline const CoeffReturnType coeff(Index row, Index col) const + inline CoeffReturnType coeff(Index row, Index col) const { return m_expression.coeff(row, col); } @@ -86,7 +73,7 @@ class ArrayWrapper : public ArrayBase > return m_expression.const_cast_derived().coeffRef(row, col); } - inline const CoeffReturnType coeff(Index index) const + inline CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } @@ -128,8 +115,14 @@ class ArrayWrapper : public ArrayBase > template inline void evalTo(Dest& dst) const { dst = m_expression; } + const typename internal::remove_all::type& + nestedExpression() const + { + return m_expression; + } + protected: - const NestedExpressionType m_expression; + NestedExpressionType m_expression; }; /** \class MatrixWrapper @@ -168,7 +161,7 @@ class MatrixWrapper : public MatrixBase > typedef typename internal::nested::type NestedExpressionType; - inline MatrixWrapper(const ExpressionType& matrix) : m_expression(matrix) {} + inline MatrixWrapper(ExpressionType& matrix) : m_expression(matrix) {} inline Index rows() const { return m_expression.rows(); } inline Index cols() const { return m_expression.cols(); } @@ -178,7 +171,7 @@ class MatrixWrapper : public MatrixBase > inline ScalarWithConstIfNotLvalue* data() { return m_expression.data(); } inline const Scalar* data() const { return m_expression.data(); } - inline const CoeffReturnType coeff(Index row, Index col) const + inline CoeffReturnType coeff(Index row, Index col) const { return m_expression.coeff(row, col); } @@ -193,7 +186,7 @@ class MatrixWrapper : public MatrixBase > return m_expression.derived().coeffRef(row, col); } - inline const CoeffReturnType coeff(Index index) const + inline CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } @@ -232,8 +225,16 @@ class MatrixWrapper : public MatrixBase > m_expression.const_cast_derived().template writePacket(index, x); } + const typename internal::remove_all::type& + nestedExpression() const + { + return m_expression; + } + protected: - const NestedExpressionType m_expression; + NestedExpressionType m_expression; }; +} // end namespace Eigen + #endif // EIGEN_ARRAYWRAPPER_H diff --git a/extern/Eigen3/Eigen/src/Core/Assign.h b/extern/Eigen3/Eigen/src/Core/Assign.h index 3a17152f043..cd29a88f0da 100644 --- a/extern/Eigen3/Eigen/src/Core/Assign.h +++ b/extern/Eigen3/Eigen/src/Core/Assign.h @@ -5,28 +5,15 @@ // Copyright (C) 2006-2010 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ASSIGN_H #define EIGEN_ASSIGN_H +namespace Eigen { + namespace internal { /*************************************************************************** @@ -152,7 +139,7 @@ struct assign_DefaultTraversal_CompleteUnrolling inner = Index % Derived1::InnerSizeAtCompileTime }; - EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) { dst.copyCoeffByOuterInner(outer, inner, src); assign_DefaultTraversal_CompleteUnrolling::run(dst, src); @@ -162,13 +149,13 @@ struct assign_DefaultTraversal_CompleteUnrolling template struct assign_DefaultTraversal_CompleteUnrolling { - EIGEN_STRONG_INLINE static void run(Derived1 &, const Derived2 &) {} + static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} }; template struct assign_DefaultTraversal_InnerUnrolling { - EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src, int outer) + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, int outer) { dst.copyCoeffByOuterInner(outer, Index, src); assign_DefaultTraversal_InnerUnrolling::run(dst, src, outer); @@ -178,7 +165,7 @@ struct assign_DefaultTraversal_InnerUnrolling template struct assign_DefaultTraversal_InnerUnrolling { - EIGEN_STRONG_INLINE static void run(Derived1 &, const Derived2 &, int) {} + static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, int) {} }; /*********************** @@ -188,7 +175,7 @@ struct assign_DefaultTraversal_InnerUnrolling template struct assign_LinearTraversal_CompleteUnrolling { - EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) { dst.copyCoeff(Index, src); assign_LinearTraversal_CompleteUnrolling::run(dst, src); @@ -198,7 +185,7 @@ struct assign_LinearTraversal_CompleteUnrolling template struct assign_LinearTraversal_CompleteUnrolling { - EIGEN_STRONG_INLINE static void run(Derived1 &, const Derived2 &) {} + static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} }; /************************** @@ -214,7 +201,7 @@ struct assign_innervec_CompleteUnrolling JointAlignment = assign_traits::JointAlignment }; - EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) { dst.template copyPacketByOuterInner(outer, inner, src); assign_innervec_CompleteUnrolling struct assign_innervec_CompleteUnrolling { - EIGEN_STRONG_INLINE static void run(Derived1 &, const Derived2 &) {} + static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} }; template struct assign_innervec_InnerUnrolling { - EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src, int outer) + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, int outer) { dst.template copyPacketByOuterInner(outer, Index, src); assign_innervec_InnerUnrolling struct assign_innervec_InnerUnrolling { - EIGEN_STRONG_INLINE static void run(Derived1 &, const Derived2 &, int) {} + static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, int) {} }; /*************************************************************************** @@ -251,24 +238,25 @@ struct assign_innervec_InnerUnrolling template::Traversal, - int Unrolling = assign_traits::Unrolling> + int Unrolling = assign_traits::Unrolling, + int Version = Specialized> struct assign_impl; /************************ *** Default traversal *** ************************/ -template -struct assign_impl +template +struct assign_impl { - inline static void run(Derived1 &, const Derived2 &) { } + static inline void run(Derived1 &, const Derived2 &) { } }; -template -struct assign_impl +template +struct assign_impl { typedef typename Derived1::Index Index; - inline static void run(Derived1 &dst, const Derived2 &src) + static inline void run(Derived1 &dst, const Derived2 &src) { const Index innerSize = dst.innerSize(); const Index outerSize = dst.outerSize(); @@ -278,21 +266,21 @@ struct assign_impl } }; -template -struct assign_impl +template +struct assign_impl { - EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) { assign_DefaultTraversal_CompleteUnrolling ::run(dst, src); } }; -template -struct assign_impl +template +struct assign_impl { typedef typename Derived1::Index Index; - EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) { const Index outerSize = dst.outerSize(); for(Index outer = 0; outer < outerSize; ++outer) @@ -305,11 +293,11 @@ struct assign_impl *** Linear traversal *** ***********************/ -template -struct assign_impl +template +struct assign_impl { typedef typename Derived1::Index Index; - inline static void run(Derived1 &dst, const Derived2 &src) + static inline void run(Derived1 &dst, const Derived2 &src) { const Index size = dst.size(); for(Index i = 0; i < size; ++i) @@ -317,10 +305,10 @@ struct assign_impl } }; -template -struct assign_impl +template +struct assign_impl { - EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) { assign_LinearTraversal_CompleteUnrolling ::run(dst, src); @@ -331,11 +319,11 @@ struct assign_impl *** Inner vectorization *** **************************/ -template -struct assign_impl +template +struct assign_impl { typedef typename Derived1::Index Index; - inline static void run(Derived1 &dst, const Derived2 &src) + static inline void run(Derived1 &dst, const Derived2 &src) { const Index innerSize = dst.innerSize(); const Index outerSize = dst.outerSize(); @@ -346,21 +334,21 @@ struct assign_impl } }; -template -struct assign_impl +template +struct assign_impl { - EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) { assign_innervec_CompleteUnrolling ::run(dst, src); } }; -template -struct assign_impl +template +struct assign_impl { typedef typename Derived1::Index Index; - EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) { const Index outerSize = dst.outerSize(); for(Index outer = 0; outer < outerSize; ++outer) @@ -398,11 +386,11 @@ struct unaligned_assign_impl } }; -template -struct assign_impl +template +struct assign_impl { typedef typename Derived1::Index Index; - EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) { const Index size = dst.size(); typedef packet_traits PacketTraits; @@ -412,7 +400,7 @@ struct assign_impl srcAlignment = assign_traits::JointAlignment }; const Index alignedStart = assign_traits::DstIsAligned ? 0 - : first_aligned(&dst.coeffRef(0), size); + : internal::first_aligned(&dst.coeffRef(0), size); const Index alignedEnd = alignedStart + ((size-alignedStart)/packetSize)*packetSize; unaligned_assign_impl::DstIsAligned!=0>::run(src,dst,0,alignedStart); @@ -426,11 +414,11 @@ struct assign_impl } }; -template -struct assign_impl +template +struct assign_impl { typedef typename Derived1::Index Index; - EIGEN_STRONG_INLINE static void run(Derived1 &dst, const Derived2 &src) + static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) { enum { size = Derived1::SizeAtCompileTime, packetSize = packet_traits::size, @@ -445,11 +433,11 @@ struct assign_impl -struct assign_impl +template +struct assign_impl { typedef typename Derived1::Index Index; - inline static void run(Derived1 &dst, const Derived2 &src) + static inline void run(Derived1 &dst, const Derived2 &src) { typedef packet_traits PacketTraits; enum { @@ -463,7 +451,7 @@ struct assign_impl const Index outerSize = dst.outerSize(); const Index alignedStep = alignable ? (packetSize - dst.outerStride() % packetSize) & packetAlignedMask : 0; Index alignedStart = ((!alignable) || assign_traits::DstIsAligned) ? 0 - : first_aligned(&dst.coeffRef(0,0), innerSize); + : internal::first_aligned(&dst.coeffRef(0,0), innerSize); for(Index outer = 0; outer < outerSize; ++outer) { @@ -531,19 +519,19 @@ struct assign_selector; template struct assign_selector { - EIGEN_STRONG_INLINE static Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.derived()); } + static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.derived()); } }; template struct assign_selector { - EIGEN_STRONG_INLINE static Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.eval()); } + static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.eval()); } }; template struct assign_selector { - EIGEN_STRONG_INLINE static Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose()); } + static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose()); } }; template struct assign_selector { - EIGEN_STRONG_INLINE static Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose().eval()); } + static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose().eval()); } }; } // end namespace internal @@ -590,4 +578,6 @@ EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const ReturnByValue< return derived(); } +} // end namespace Eigen + #endif // EIGEN_ASSIGN_H diff --git a/extern/Eigen3/Eigen/src/Core/Assign_MKL.h b/extern/Eigen3/Eigen/src/Core/Assign_MKL.h new file mode 100644 index 00000000000..428c6367b92 --- /dev/null +++ b/extern/Eigen3/Eigen/src/Core/Assign_MKL.h @@ -0,0 +1,224 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * MKL VML support for coefficient-wise unary Eigen expressions like a=b.sin() + ******************************************************************************** +*/ + +#ifndef EIGEN_ASSIGN_VML_H +#define EIGEN_ASSIGN_VML_H + +namespace Eigen { + +namespace internal { + +template struct vml_call +{ enum { IsSupported = 0 }; }; + +template +class vml_assign_traits +{ + private: + enum { + DstHasDirectAccess = Dst::Flags & DirectAccessBit, + SrcHasDirectAccess = Src::Flags & DirectAccessBit, + + StorageOrdersAgree = (int(Dst::IsRowMajor) == int(Src::IsRowMajor)), + InnerSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::SizeAtCompileTime) + : int(Dst::Flags)&RowMajorBit ? int(Dst::ColsAtCompileTime) + : int(Dst::RowsAtCompileTime), + InnerMaxSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::MaxSizeAtCompileTime) + : int(Dst::Flags)&RowMajorBit ? int(Dst::MaxColsAtCompileTime) + : int(Dst::MaxRowsAtCompileTime), + MaxSizeAtCompileTime = Dst::SizeAtCompileTime, + + MightEnableVml = vml_call::IsSupported && StorageOrdersAgree && DstHasDirectAccess && SrcHasDirectAccess + && Src::InnerStrideAtCompileTime==1 && Dst::InnerStrideAtCompileTime==1, + MightLinearize = MightEnableVml && (int(Dst::Flags) & int(Src::Flags) & LinearAccessBit), + VmlSize = MightLinearize ? MaxSizeAtCompileTime : InnerMaxSize, + LargeEnough = VmlSize==Dynamic || VmlSize>=EIGEN_MKL_VML_THRESHOLD, + MayEnableVml = MightEnableVml && LargeEnough, + MayLinearize = MayEnableVml && MightLinearize + }; + public: + enum { + Traversal = MayLinearize ? LinearVectorizedTraversal + : MayEnableVml ? InnerVectorizedTraversal + : DefaultTraversal + }; +}; + +template::Traversal > +struct vml_assign_impl + : assign_impl,Traversal,Unrolling,BuiltIn> +{ +}; + +template +struct vml_assign_impl +{ + typedef typename Derived1::Scalar Scalar; + typedef typename Derived1::Index Index; + static inline void run(Derived1& dst, const CwiseUnaryOp& src) + { + // in case we want to (or have to) skip VML at runtime we can call: + // assign_impl,Traversal,Unrolling,BuiltIn>::run(dst,src); + const Index innerSize = dst.innerSize(); + const Index outerSize = dst.outerSize(); + for(Index outer = 0; outer < outerSize; ++outer) { + const Scalar *src_ptr = src.IsRowMajor ? &(src.nestedExpression().coeffRef(outer,0)) : + &(src.nestedExpression().coeffRef(0, outer)); + Scalar *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer,0)) : &(dst.coeffRef(0, outer)); + vml_call::run(src.functor(), innerSize, src_ptr, dst_ptr ); + } + } +}; + +template +struct vml_assign_impl +{ + static inline void run(Derived1& dst, const CwiseUnaryOp& src) + { + // in case we want to (or have to) skip VML at runtime we can call: + // assign_impl,Traversal,Unrolling,BuiltIn>::run(dst,src); + vml_call::run(src.functor(), dst.size(), src.nestedExpression().data(), dst.data() ); + } +}; + +// Macroses + +#define EIGEN_MKL_VML_SPECIALIZE_ASSIGN(TRAVERSAL,UNROLLING) \ + template \ + struct assign_impl, TRAVERSAL, UNROLLING, Specialized> { \ + static inline void run(Derived1 &dst, const Eigen::CwiseUnaryOp &src) { \ + vml_assign_impl::run(dst, src); \ + } \ + }; + +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(DefaultTraversal,NoUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(DefaultTraversal,CompleteUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(DefaultTraversal,InnerUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearTraversal,NoUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearTraversal,CompleteUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(InnerVectorizedTraversal,NoUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(InnerVectorizedTraversal,CompleteUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(InnerVectorizedTraversal,InnerUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearVectorizedTraversal,CompleteUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearVectorizedTraversal,NoUnrolling) +EIGEN_MKL_VML_SPECIALIZE_ASSIGN(SliceVectorizedTraversal,NoUnrolling) + + +#if !defined (EIGEN_FAST_MATH) || (EIGEN_FAST_MATH != 1) +#define EIGEN_MKL_VML_MODE VML_HA +#else +#define EIGEN_MKL_VML_MODE VML_LA +#endif + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE) \ + template<> struct vml_call< scalar_##EIGENOP##_op > { \ + enum { IsSupported = 1 }; \ + static inline void run( const scalar_##EIGENOP##_op& /*func*/, \ + int size, const EIGENTYPE* src, EIGENTYPE* dst) { \ + VMLOP(size, (const VMLTYPE*)src, (VMLTYPE*)dst); \ + } \ + }; + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE) \ + template<> struct vml_call< scalar_##EIGENOP##_op > { \ + enum { IsSupported = 1 }; \ + static inline void run( const scalar_##EIGENOP##_op& /*func*/, \ + int size, const EIGENTYPE* src, EIGENTYPE* dst) { \ + MKL_INT64 vmlMode = EIGEN_MKL_VML_MODE; \ + VMLOP(size, (const VMLTYPE*)src, (VMLTYPE*)dst, vmlMode); \ + } \ + }; + +#define EIGEN_MKL_VML_DECLARE_POW_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE) \ + template<> struct vml_call< scalar_##EIGENOP##_op > { \ + enum { IsSupported = 1 }; \ + static inline void run( const scalar_##EIGENOP##_op& func, \ + int size, const EIGENTYPE* src, EIGENTYPE* dst) { \ + EIGENTYPE exponent = func.m_exponent; \ + MKL_INT64 vmlMode = EIGEN_MKL_VML_MODE; \ + VMLOP(&size, (const VMLTYPE*)src, (const VMLTYPE*)&exponent, \ + (VMLTYPE*)dst, &vmlMode); \ + } \ + }; + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vs##VMLOP, float, float) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vd##VMLOP, double, double) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX(EIGENOP, VMLOP) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vc##VMLOP, scomplex, MKL_Complex8) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vz##VMLOP, dcomplex, MKL_Complex16) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS(EIGENOP, VMLOP) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX(EIGENOP, VMLOP) + + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL_LA(EIGENOP, VMLOP) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vms##VMLOP, float, float) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmd##VMLOP, double, double) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX_LA(EIGENOP, VMLOP) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmc##VMLOP, scomplex, MKL_Complex8) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmz##VMLOP, dcomplex, MKL_Complex16) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(EIGENOP, VMLOP) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL_LA(EIGENOP, VMLOP) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX_LA(EIGENOP, VMLOP) + + +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(sin, Sin) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(asin, Asin) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(cos, Cos) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(acos, Acos) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(tan, Tan) +//EIGEN_MKL_VML_DECLARE_UNARY_CALLS(abs, Abs) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(exp, Exp) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(log, Ln) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(sqrt, Sqrt) + +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(square, Sqr) + +// The vm*powx functions are not avaibale in the windows version of MKL. +#ifdef _WIN32 +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmspowx_, float, float) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmdpowx_, double, double) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmcpowx_, scomplex, MKL_Complex8) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmzpowx_, dcomplex, MKL_Complex16) +#endif + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_ASSIGN_VML_H diff --git a/extern/Eigen3/Eigen/src/Core/BandMatrix.h b/extern/Eigen3/Eigen/src/Core/BandMatrix.h index 2570d7b559f..ffd7fe8b301 100644 --- a/extern/Eigen3/Eigen/src/Core/BandMatrix.h +++ b/extern/Eigen3/Eigen/src/Core/BandMatrix.h @@ -3,30 +3,16 @@ // // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_BANDMATRIX_H #define EIGEN_BANDMATRIX_H -namespace internal { +namespace Eigen { +namespace internal { template class BandMatrixBase : public EigenBase @@ -343,4 +329,6 @@ class TridiagonalMatrix : public BandMatrix // Copyright (C) 2006-2010 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_BLOCK_H #define EIGEN_BLOCK_H +namespace Eigen { + /** \class Block * \ingroup Core_Module * @@ -242,6 +229,21 @@ template::type& nestedExpression() const + { + return m_xpr; + } + + Index startRow() const + { + return m_startRow.value(); + } + + Index startCol() const + { + return m_startCol.value(); + } + protected: const typename XprType::Nested m_xpr; @@ -304,6 +306,11 @@ class Block init(); } + const typename internal::remove_all::type& nestedExpression() const + { + return m_xpr; + } + /** \sa MapBase::innerStride() */ inline Index innerStride() const { @@ -341,9 +348,10 @@ class Block : m_xpr.innerStride(); } - const typename XprType::Nested m_xpr; + typename XprType::Nested m_xpr; Index m_outerStride; }; +} // end namespace Eigen #endif // EIGEN_BLOCK_H diff --git a/extern/Eigen3/Eigen/src/Core/BooleanRedux.h b/extern/Eigen3/Eigen/src/Core/BooleanRedux.h index 5c3444a57c9..57efd8e6953 100644 --- a/extern/Eigen3/Eigen/src/Core/BooleanRedux.h +++ b/extern/Eigen3/Eigen/src/Core/BooleanRedux.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ALLANDANY_H #define EIGEN_ALLANDANY_H +namespace Eigen { + namespace internal { template @@ -35,7 +22,7 @@ struct all_unroller row = (UnrollCount-1) % Derived::RowsAtCompileTime }; - inline static bool run(const Derived &mat) + static inline bool run(const Derived &mat) { return all_unroller::run(mat) && mat.coeff(row, col); } @@ -44,13 +31,13 @@ struct all_unroller template struct all_unroller { - inline static bool run(const Derived &mat) { return mat.coeff(0, 0); } + static inline bool run(const Derived &mat) { return mat.coeff(0, 0); } }; template struct all_unroller { - inline static bool run(const Derived &) { return false; } + static inline bool run(const Derived &) { return false; } }; template @@ -61,7 +48,7 @@ struct any_unroller row = (UnrollCount-1) % Derived::RowsAtCompileTime }; - inline static bool run(const Derived &mat) + static inline bool run(const Derived &mat) { return any_unroller::run(mat) || mat.coeff(row, col); } @@ -70,13 +57,13 @@ struct any_unroller template struct any_unroller { - inline static bool run(const Derived &mat) { return mat.coeff(0, 0); } + static inline bool run(const Derived &mat) { return mat.coeff(0, 0); } }; template struct any_unroller { - inline static bool run(const Derived &) { return false; } + static inline bool run(const Derived &) { return false; } }; } // end namespace internal @@ -146,4 +133,6 @@ inline typename DenseBase::Index DenseBase::count() const return derived().template cast().template cast().sum(); } +} // end namespace Eigen + #endif // EIGEN_ALLANDANY_H diff --git a/extern/Eigen3/Eigen/src/Core/CommaInitializer.h b/extern/Eigen3/Eigen/src/Core/CommaInitializer.h index 92422bf2fa0..4adce64143c 100644 --- a/extern/Eigen3/Eigen/src/Core/CommaInitializer.h +++ b/extern/Eigen3/Eigen/src/Core/CommaInitializer.h @@ -4,28 +4,15 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_COMMAINITIALIZER_H #define EIGEN_COMMAINITIALIZER_H +namespace Eigen { + /** \class CommaInitializer * \ingroup Core_Module * @@ -147,4 +134,6 @@ DenseBase::operator<<(const DenseBase& other) return CommaInitializer(*static_cast(this), other); } +} // end namespace Eigen + #endif // EIGEN_COMMAINITIALIZER_H diff --git a/extern/Eigen3/Eigen/src/Core/CwiseBinaryOp.h b/extern/Eigen3/Eigen/src/Core/CwiseBinaryOp.h index 7386b2e1843..1b93af31b60 100644 --- a/extern/Eigen3/Eigen/src/Core/CwiseBinaryOp.h +++ b/extern/Eigen3/Eigen/src/Core/CwiseBinaryOp.h @@ -4,28 +4,15 @@ // Copyright (C) 2008-2009 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CWISE_BINARY_OP_H #define EIGEN_CWISE_BINARY_OP_H +namespace Eigen { + /** \class CwiseBinaryOp * \ingroup Core_Module * @@ -167,8 +154,8 @@ class CwiseBinaryOp : internal::no_assignment_operator, const BinaryOp& functor() const { return m_functor; } protected: - const LhsNested m_lhs; - const RhsNested m_rhs; + LhsNested m_lhs; + RhsNested m_rhs; const BinaryOp m_functor; }; @@ -237,4 +224,6 @@ MatrixBase::operator+=(const MatrixBase& other) return derived(); } +} // end namespace Eigen + #endif // EIGEN_CWISE_BINARY_OP_H diff --git a/extern/Eigen3/Eigen/src/Core/CwiseNullaryOp.h b/extern/Eigen3/Eigen/src/Core/CwiseNullaryOp.h index c616e7ae13d..2635a62b07b 100644 --- a/extern/Eigen3/Eigen/src/Core/CwiseNullaryOp.h +++ b/extern/Eigen3/Eigen/src/Core/CwiseNullaryOp.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CWISE_NULLARY_OP_H #define EIGEN_CWISE_NULLARY_OP_H +namespace Eigen { + /** \class CwiseNullaryOp * \ingroup Core_Module * @@ -101,6 +88,9 @@ class CwiseNullaryOp : internal::no_assignment_operator, return m_functor.packetOp(index); } + /** \returns the functor representing the nullary operation */ + const NullaryOp& functor() const { return m_functor; } + protected: const internal::variable_if_dynamic m_rows; const internal::variable_if_dynamic m_cols; @@ -238,6 +228,8 @@ DenseBase::Constant(const Scalar& value) * assumed to be a(0), a(1), ..., a(size). This assumption allows for better vectorization * and yields faster code than the random access version. * + * When size is set to 1, a vector of length 1 containing 'high' is returned. + * * \only_for_vectors * * Example: \include DenseBase_LinSpaced_seq.cpp @@ -270,6 +262,7 @@ DenseBase::LinSpaced(Sequential_t, const Scalar& low, const Scalar& hig * \brief Sets a linearly space vector. * * The function generates 'size' equally spaced values in the closed interval [low,high]. + * When size is set to 1, a vector of length 1 containing 'high' is returned. * * \only_for_vectors * @@ -381,6 +374,7 @@ PlainObjectBase::setConstant(Index rows, Index cols, const Scalar& valu * \brief Sets a linearly space vector. * * The function generates 'size' equally spaced values in the closed interval [low,high]. + * When size is set to 1, a vector of length 1 containing 'high' is returned. * * \only_for_vectors * @@ -396,6 +390,23 @@ EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(Index size, const return derived() = Derived::NullaryExpr(size, internal::linspaced_op(low,high,size)); } +/** + * \brief Sets a linearly space vector. + * + * The function fill *this with equally spaced values in the closed interval [low,high]. + * When size is set to 1, a vector of length 1 containing 'high' is returned. + * + * \only_for_vectors + * + * \sa setLinSpaced(Index, const Scalar&, const Scalar&), CwiseNullaryOp + */ +template +EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(const Scalar& low, const Scalar& high) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return setLinSpaced(size(), low, high); +} + // zero: /** \returns an expression of a zero matrix. @@ -848,4 +859,6 @@ template EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitW() { return Derived::Unit(3); } +} // end namespace Eigen + #endif // EIGEN_CWISE_NULLARY_OP_H diff --git a/extern/Eigen3/Eigen/src/Core/CwiseUnaryOp.h b/extern/Eigen3/Eigen/src/Core/CwiseUnaryOp.h index 958571d64bf..063355ae521 100644 --- a/extern/Eigen3/Eigen/src/Core/CwiseUnaryOp.h +++ b/extern/Eigen3/Eigen/src/Core/CwiseUnaryOp.h @@ -4,28 +4,15 @@ // Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CWISE_UNARY_OP_H #define EIGEN_CWISE_UNARY_OP_H +namespace Eigen { + /** \class CwiseUnaryOp * \ingroup Core_Module * @@ -95,7 +82,7 @@ class CwiseUnaryOp : internal::no_assignment_operator, nestedExpression() { return m_xpr.const_cast_derived(); } protected: - const typename XprType::Nested m_xpr; + typename XprType::Nested m_xpr; const UnaryOp m_functor; }; @@ -134,4 +121,6 @@ class CwiseUnaryOpImpl } }; +} // end namespace Eigen + #endif // EIGEN_CWISE_UNARY_OP_H diff --git a/extern/Eigen3/Eigen/src/Core/CwiseUnaryView.h b/extern/Eigen3/Eigen/src/Core/CwiseUnaryView.h index d24ef037314..66f73a9505b 100644 --- a/extern/Eigen3/Eigen/src/Core/CwiseUnaryView.h +++ b/extern/Eigen3/Eigen/src/Core/CwiseUnaryView.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CWISE_UNARY_VIEW_H #define EIGEN_CWISE_UNARY_VIEW_H +namespace Eigen { + /** \class CwiseUnaryView * \ingroup Core_Module * @@ -97,7 +84,7 @@ class CwiseUnaryView : internal::no_assignment_operator, protected: // FIXME changed from MatrixType::Nested because of a weird compilation error with sun CC - const typename internal::nested::type m_matrix; + typename internal::nested::type m_matrix; ViewOp m_functor; }; @@ -143,6 +130,6 @@ class CwiseUnaryViewImpl } }; - +} // end namespace Eigen #endif // EIGEN_CWISE_UNARY_VIEW_H diff --git a/extern/Eigen3/Eigen/src/Core/DenseBase.h b/extern/Eigen3/Eigen/src/Core/DenseBase.h index 920904f243a..1cc0314ef0b 100644 --- a/extern/Eigen3/Eigen/src/Core/DenseBase.h +++ b/extern/Eigen3/Eigen/src/Core/DenseBase.h @@ -4,28 +4,15 @@ // Copyright (C) 2007-2010 Benoit Jacob // Copyright (C) 2008-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_DENSEBASE_H #define EIGEN_DENSEBASE_H +namespace Eigen { + /** \class DenseBase * \ingroup Core_Module * @@ -376,12 +363,13 @@ template class DenseBase inline Derived& operator*=(const Scalar& other); inline Derived& operator/=(const Scalar& other); + typedef typename internal::add_const_on_value_type::type>::type EvalReturnType; /** \returns the matrix or vector obtained by evaluating this expression. * * Notice that in the case of a plain matrix or vector (not an expression) this function just returns * a const reference, in order to avoid a useless copy. */ - EIGEN_STRONG_INLINE const typename internal::eval::type eval() const + EIGEN_STRONG_INLINE EvalReturnType eval() const { // Even though MSVC does not honor strong inlining when the return type // is a dynamic matrix, we desperately need strong inlining for fixed @@ -540,4 +528,6 @@ template class DenseBase template explicit DenseBase(const DenseBase&); }; +} // end namespace Eigen + #endif // EIGEN_DENSEBASE_H diff --git a/extern/Eigen3/Eigen/src/Core/DenseCoeffsBase.h b/extern/Eigen3/Eigen/src/Core/DenseCoeffsBase.h index e45238fb584..72704c2d79f 100644 --- a/extern/Eigen3/Eigen/src/Core/DenseCoeffsBase.h +++ b/extern/Eigen3/Eigen/src/Core/DenseCoeffsBase.h @@ -3,28 +3,15 @@ // // Copyright (C) 2006-2010 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_DENSECOEFFSBASE_H #define EIGEN_DENSECOEFFSBASE_H +namespace Eigen { + namespace internal { template struct add_const_on_value_type_if_arithmetic { @@ -710,16 +697,16 @@ namespace internal { template struct first_aligned_impl { - inline static typename Derived::Index run(const Derived&) + static inline typename Derived::Index run(const Derived&) { return 0; } }; template struct first_aligned_impl { - inline static typename Derived::Index run(const Derived& m) + static inline typename Derived::Index run(const Derived& m) { - return first_aligned(&m.const_cast_derived().coeffRef(0,0), m.size()); + return internal::first_aligned(&m.const_cast_derived().coeffRef(0,0), m.size()); } }; @@ -729,7 +716,7 @@ struct first_aligned_impl * documentation. */ template -inline static typename Derived::Index first_aligned(const Derived& m) +static inline typename Derived::Index first_aligned(const Derived& m) { return first_aligned_impl @@ -762,4 +749,6 @@ struct outer_stride_at_compile_time } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_DENSECOEFFSBASE_H diff --git a/extern/Eigen3/Eigen/src/Core/DenseStorage.h b/extern/Eigen3/Eigen/src/Core/DenseStorage.h index 813053b00dd..1fc2daf2c40 100644 --- a/extern/Eigen3/Eigen/src/Core/DenseStorage.h +++ b/extern/Eigen3/Eigen/src/Core/DenseStorage.h @@ -5,24 +5,9 @@ // Copyright (C) 2006-2009 Benoit Jacob // Copyright (C) 2010 Hauke Heibel // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MATRIXSTORAGE_H #define EIGEN_MATRIXSTORAGE_H @@ -33,6 +18,8 @@ #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN #endif +namespace Eigen { + namespace internal { struct constructor_without_unaligned_array_assert {}; @@ -104,8 +91,8 @@ template class DenseSt : m_data(internal::constructor_without_unaligned_array_assert()) {} inline DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); } - inline static DenseIndex rows(void) {return _Rows;} - inline static DenseIndex cols(void) {return _Cols;} + static inline DenseIndex rows(void) {return _Rows;} + static inline DenseIndex cols(void) {return _Cols;} inline void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} inline void resize(DenseIndex,DenseIndex,DenseIndex) {} inline const T *data() const { return m_data.array; } @@ -120,14 +107,24 @@ template class DenseStorage class DenseStorage +: public DenseStorage { }; + +template class DenseStorage +: public DenseStorage { }; + +template class DenseStorage +: public DenseStorage { }; + // dynamic-size matrix with fixed-size storage template class DenseStorage { @@ -241,7 +238,7 @@ template class DenseStorage(m_data, _Rows*m_cols); } inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } - inline static DenseIndex rows(void) {return _Rows;} + static inline DenseIndex rows(void) {return _Rows;} inline DenseIndex cols(void) const {return m_cols;} inline void conservativeResize(DenseIndex size, DenseIndex, DenseIndex cols) { @@ -278,7 +275,7 @@ template class DenseStorage(m_data, _Cols*m_rows); } inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } inline DenseIndex rows(void) const {return m_rows;} - inline static DenseIndex cols(void) {return _Cols;} + static inline DenseIndex cols(void) {return _Cols;} inline void conservativeResize(DenseIndex size, DenseIndex rows, DenseIndex) { m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*_Cols); @@ -301,4 +298,6 @@ template class DenseStorage +// Copyright (C) 2009-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_DIAGONAL_H #define EIGEN_DIAGONAL_H +namespace Eigen { + /** \class Diagonal * \ingroup Core_Module * @@ -53,16 +41,15 @@ struct traits > typedef typename remove_reference::type _MatrixTypeNested; typedef typename MatrixType::StorageKind StorageKind; enum { - AbsDiagIndex = DiagIndex<0 ? -DiagIndex : DiagIndex, // only used if DiagIndex != Dynamic - // FIXME these computations are broken in the case where the matrix is rectangular and DiagIndex!=0 RowsAtCompileTime = (int(DiagIndex) == Dynamic || int(MatrixType::SizeAtCompileTime) == Dynamic) ? Dynamic - : (EIGEN_SIZE_MIN_PREFER_DYNAMIC(MatrixType::RowsAtCompileTime, - MatrixType::ColsAtCompileTime) - AbsDiagIndex), + : (EIGEN_PLAIN_ENUM_MIN(MatrixType::RowsAtCompileTime - EIGEN_PLAIN_ENUM_MAX(-DiagIndex, 0), + MatrixType::ColsAtCompileTime - EIGEN_PLAIN_ENUM_MAX( DiagIndex, 0))), ColsAtCompileTime = 1, MaxRowsAtCompileTime = int(MatrixType::MaxSizeAtCompileTime) == Dynamic ? Dynamic : DiagIndex == Dynamic ? EIGEN_SIZE_MIN_PREFER_FIXED(MatrixType::MaxRowsAtCompileTime, - MatrixType::MaxColsAtCompileTime) - : (EIGEN_SIZE_MIN_PREFER_FIXED(MatrixType::MaxRowsAtCompileTime, MatrixType::MaxColsAtCompileTime) - AbsDiagIndex), + MatrixType::MaxColsAtCompileTime) + : (EIGEN_PLAIN_ENUM_MIN(MatrixType::MaxRowsAtCompileTime - EIGEN_PLAIN_ENUM_MAX(-DiagIndex, 0), + MatrixType::MaxColsAtCompileTime - EIGEN_PLAIN_ENUM_MAX( DiagIndex, 0))), MaxColsAtCompileTime = 1, MaskLvalueBit = is_lvalue::value ? LvalueBit : 0, Flags = (unsigned int)_MatrixTypeNested::Flags & (HereditaryBits | LinearAccessBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit, @@ -101,6 +88,15 @@ template class Diagonal return 0; } + typedef typename internal::conditional< + internal::is_lvalue::value, + Scalar, + const Scalar + >::type ScalarWithConstIfNotLvalue; + + inline ScalarWithConstIfNotLvalue* data() { return &(m_matrix.const_cast_derived().coeffRef(rowOffset(), colOffset())); } + inline const Scalar* data() const { return &(m_matrix.const_cast_derived().coeffRef(rowOffset(), colOffset())); } + inline Scalar& coeffRef(Index row, Index) { EIGEN_STATIC_ASSERT_LVALUE(MatrixType) @@ -133,8 +129,19 @@ template class Diagonal return m_matrix.coeff(index+rowOffset(), index+colOffset()); } + const typename internal::remove_all::type& + nestedExpression() const + { + return m_matrix; + } + + int index() const + { + return m_index.value(); + } + protected: - const typename MatrixType::Nested m_matrix; + typename MatrixType::Nested m_matrix; const internal::variable_if_dynamic m_index; private: @@ -224,4 +231,6 @@ MatrixBase::diagonal() const return derived(); } +} // end namespace Eigen + #endif // EIGEN_DIAGONAL_H diff --git a/extern/Eigen3/Eigen/src/Core/DiagonalMatrix.h b/extern/Eigen3/Eigen/src/Core/DiagonalMatrix.h index f41a74bfae7..88190da684d 100644 --- a/extern/Eigen3/Eigen/src/Core/DiagonalMatrix.h +++ b/extern/Eigen3/Eigen/src/Core/DiagonalMatrix.h @@ -4,28 +4,15 @@ // Copyright (C) 2009 Gael Guennebaud // Copyright (C) 2007-2009 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_DIAGONALMATRIX_H #define EIGEN_DIAGONALMATRIX_H +namespace Eigen { + #ifndef EIGEN_PARSED_BY_DOXYGEN template class DiagonalBase : public EigenBase @@ -72,7 +59,7 @@ class DiagonalBase : public EigenBase const DiagonalProduct operator*(const MatrixBase &matrix) const; - inline const DiagonalWrapper, const DiagonalVectorType> > + inline const DiagonalWrapper, const DiagonalVectorType> > inverse() const { return diagonal().cwiseInverse(); @@ -251,13 +238,13 @@ class DiagonalWrapper #endif /** Constructor from expression of diagonal coefficients to wrap. */ - inline DiagonalWrapper(const DiagonalVectorType& diagonal) : m_diagonal(diagonal) {} + inline DiagonalWrapper(DiagonalVectorType& diagonal) : m_diagonal(diagonal) {} /** \returns a const reference to the wrapped expression of diagonal coefficients. */ const DiagonalVectorType& diagonal() const { return m_diagonal; } protected: - const typename DiagonalVectorType::Nested m_diagonal; + typename DiagonalVectorType::Nested m_diagonal; }; /** \returns a pseudo-expression of a diagonal matrix with *this as vector of diagonal coefficients @@ -303,4 +290,6 @@ bool MatrixBase::isDiagonal(RealScalar prec) const return true; } +} // end namespace Eigen + #endif // EIGEN_DIAGONALMATRIX_H diff --git a/extern/Eigen3/Eigen/src/Core/DiagonalProduct.h b/extern/Eigen3/Eigen/src/Core/DiagonalProduct.h index de0c6ed11b7..598c6b3e19a 100644 --- a/extern/Eigen3/Eigen/src/Core/DiagonalProduct.h +++ b/extern/Eigen3/Eigen/src/Core/DiagonalProduct.h @@ -4,28 +4,15 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2007-2009 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_DIAGONALPRODUCT_H #define EIGEN_DIAGONALPRODUCT_H +namespace Eigen { + namespace internal { template struct traits > @@ -107,8 +94,8 @@ class DiagonalProduct : internal::no_assignment_operator, m_diagonal.diagonal().template packet(id)); } - const typename MatrixType::Nested m_matrix; - const typename DiagonalType::Nested m_diagonal; + typename MatrixType::Nested m_matrix; + typename DiagonalType::Nested m_diagonal; }; /** \returns the diagonal matrix product of \c *this by the diagonal matrix \a diagonal. @@ -131,5 +118,6 @@ DiagonalBase::operator*(const MatrixBase &matrix return DiagonalProduct(matrix.derived(), derived()); } +} // end namespace Eigen #endif // EIGEN_DIAGONALPRODUCT_H diff --git a/extern/Eigen3/Eigen/src/Core/Dot.h b/extern/Eigen3/Eigen/src/Core/Dot.h index 42da7849896..ae9274e36dd 100644 --- a/extern/Eigen3/Eigen/src/Core/Dot.h +++ b/extern/Eigen3/Eigen/src/Core/Dot.h @@ -3,28 +3,15 @@ // // Copyright (C) 2006-2008, 2010 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_DOT_H #define EIGEN_DOT_H +namespace Eigen { + namespace internal { // helper function for dot(). The problem is that if we put that in the body of dot(), then upon calling dot @@ -176,7 +163,7 @@ template struct lpNorm_selector { typedef typename NumTraits::Scalar>::Real RealScalar; - inline static RealScalar run(const MatrixBase& m) + static inline RealScalar run(const MatrixBase& m) { return pow(m.cwiseAbs().array().pow(p).sum(), RealScalar(1)/p); } @@ -185,7 +172,7 @@ struct lpNorm_selector template struct lpNorm_selector { - inline static typename NumTraits::Scalar>::Real run(const MatrixBase& m) + static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) { return m.cwiseAbs().sum(); } @@ -194,7 +181,7 @@ struct lpNorm_selector template struct lpNorm_selector { - inline static typename NumTraits::Scalar>::Real run(const MatrixBase& m) + static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) { return m.norm(); } @@ -203,7 +190,7 @@ struct lpNorm_selector template struct lpNorm_selector { - inline static typename NumTraits::Scalar>::Real run(const MatrixBase& m) + static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) { return m.cwiseAbs().maxCoeff(); } @@ -269,4 +256,6 @@ bool MatrixBase::isUnitary(RealScalar prec) const return true; } +} // end namespace Eigen + #endif // EIGEN_DOT_H diff --git a/extern/Eigen3/Eigen/src/Core/EigenBase.h b/extern/Eigen3/Eigen/src/Core/EigenBase.h index 0472539af33..0bbd28bec21 100644 --- a/extern/Eigen3/Eigen/src/Core/EigenBase.h +++ b/extern/Eigen3/Eigen/src/Core/EigenBase.h @@ -4,28 +4,14 @@ // Copyright (C) 2009 Benoit Jacob // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_EIGENBASE_H #define EIGEN_EIGENBASE_H +namespace Eigen { /** Common base class for all classes T such that MatrixBase has an operator=(T) and a constructor MatrixBase(T). * @@ -169,4 +155,6 @@ inline void MatrixBase::applyOnTheLeft(const EigenBase &o other.derived().applyThisOnTheLeft(derived()); } +} // end namespace Eigen + #endif // EIGEN_EIGENBASE_H diff --git a/extern/Eigen3/Eigen/src/Core/Flagged.h b/extern/Eigen3/Eigen/src/Core/Flagged.h index 458213ab553..1f2955fc1de 100644 --- a/extern/Eigen3/Eigen/src/Core/Flagged.h +++ b/extern/Eigen3/Eigen/src/Core/Flagged.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_FLAGGED_H #define EIGEN_FLAGGED_H +namespace Eigen { + /** \class Flagged * \ingroup Core_Module * @@ -148,4 +135,6 @@ DenseBase::flagged() const return derived(); } +} // end namespace Eigen + #endif // EIGEN_FLAGGED_H diff --git a/extern/Eigen3/Eigen/src/Core/ForceAlignedAccess.h b/extern/Eigen3/Eigen/src/Core/ForceAlignedAccess.h index 11c1f8f709a..807c7a29346 100644 --- a/extern/Eigen3/Eigen/src/Core/ForceAlignedAccess.h +++ b/extern/Eigen3/Eigen/src/Core/ForceAlignedAccess.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_FORCEALIGNEDACCESS_H #define EIGEN_FORCEALIGNEDACCESS_H +namespace Eigen { + /** \class ForceAlignedAccess * \ingroup Core_Module * @@ -154,4 +141,6 @@ MatrixBase::forceAlignedAccessIf() return derived(); } +} // end namespace Eigen + #endif // EIGEN_FORCEALIGNEDACCESS_H diff --git a/extern/Eigen3/Eigen/src/Core/Functors.h b/extern/Eigen3/Eigen/src/Core/Functors.h index 54636e0d459..278c46c6b61 100644 --- a/extern/Eigen3/Eigen/src/Core/Functors.h +++ b/extern/Eigen3/Eigen/src/Core/Functors.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_FUNCTORS_H #define EIGEN_FUNCTORS_H +namespace Eigen { + namespace internal { // associative functors: @@ -178,6 +165,18 @@ struct functor_traits > { enum { Cost = 5 * NumTraits::MulCost, PacketAccess=0 }; }; +/** \internal + * \brief Template functor to compute the pow of two scalars + */ +template struct scalar_binary_pow_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_binary_pow_op) + inline Scalar operator() (const Scalar& a, const OtherScalar& b) const { return internal::pow(a, b); } +}; +template +struct functor_traits > { + enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; +}; + // other binary functors: /** \internal @@ -220,6 +219,38 @@ struct functor_traits > { }; }; +/** \internal + * \brief Template functor to compute the and of two booleans + * + * \sa class CwiseBinaryOp, ArrayBase::operator&& + */ +struct scalar_boolean_and_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_and_op) + EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a && b; } +}; +template<> struct functor_traits { + enum { + Cost = NumTraits::AddCost, + PacketAccess = false + }; +}; + +/** \internal + * \brief Template functor to compute the or of two booleans + * + * \sa class CwiseBinaryOp, ArrayBase::operator|| + */ +struct scalar_boolean_or_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_or_op) + EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a || b; } +}; +template<> struct functor_traits { + enum { + Cost = NumTraits::AddCost, + PacketAccess = false + }; +}; + // unary functors: /** \internal @@ -249,7 +280,7 @@ struct functor_traits > template struct scalar_abs_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_abs_op) typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { return abs(a); } + EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { return internal::abs(a); } template EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pabs(a); } @@ -271,7 +302,7 @@ struct functor_traits > template struct scalar_abs2_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_abs2_op) typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { return abs2(a); } + EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { return internal::abs2(a); } template EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pmul(a,a); } @@ -287,7 +318,7 @@ struct functor_traits > */ template struct scalar_conjugate_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_conjugate_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return conj(a); } + EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return internal::conj(a); } template EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pconj(a); } }; @@ -324,7 +355,7 @@ template struct scalar_real_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_real_op) typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return real(a); } + EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return internal::real(a); } }; template struct functor_traits > @@ -339,7 +370,7 @@ template struct scalar_imag_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_imag_op) typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return imag(a); } + EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return internal::imag(a); } }; template struct functor_traits > @@ -354,7 +385,7 @@ template struct scalar_real_ref_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_real_ref_op) typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return real_ref(*const_cast(&a)); } + EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return internal::real_ref(*const_cast(&a)); } }; template struct functor_traits > @@ -369,7 +400,7 @@ template struct scalar_imag_ref_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_imag_ref_op) typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return imag_ref(*const_cast(&a)); } + EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return internal::imag_ref(*const_cast(&a)); } }; template struct functor_traits > @@ -383,7 +414,7 @@ struct functor_traits > */ template struct scalar_exp_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_exp_op) - inline const Scalar operator() (const Scalar& a) const { return exp(a); } + inline const Scalar operator() (const Scalar& a) const { return internal::exp(a); } typedef typename packet_traits::type Packet; inline Packet packetOp(const Packet& a) const { return internal::pexp(a); } }; @@ -399,7 +430,7 @@ struct functor_traits > */ template struct scalar_log_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_log_op) - inline const Scalar operator() (const Scalar& a) const { return log(a); } + inline const Scalar operator() (const Scalar& a) const { return internal::log(a); } typedef typename packet_traits::type Packet; inline Packet packetOp(const Packet& a) const { return internal::plog(a); } }; @@ -584,7 +615,7 @@ template struct functor_traits< linspaced_o template struct linspaced_op { typedef typename packet_traits::type Packet; - linspaced_op(Scalar low, Scalar high, int num_steps) : impl(low, (high-low)/(num_steps-1)) {} + linspaced_op(Scalar low, Scalar high, int num_steps) : impl((num_steps==1 ? high : low), (num_steps==1 ? Scalar() : (high-low)/(num_steps-1))) {} template EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return impl(i); } @@ -657,7 +688,7 @@ struct functor_traits > */ template struct scalar_sqrt_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_sqrt_op) - inline const Scalar operator() (const Scalar& a) const { return sqrt(a); } + inline const Scalar operator() (const Scalar& a) const { return internal::sqrt(a); } typedef typename packet_traits::type Packet; inline Packet packetOp(const Packet& a) const { return internal::psqrt(a); } }; @@ -675,7 +706,7 @@ struct functor_traits > */ template struct scalar_cos_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_cos_op) - inline Scalar operator() (const Scalar& a) const { return cos(a); } + inline Scalar operator() (const Scalar& a) const { return internal::cos(a); } typedef typename packet_traits::type Packet; inline Packet packetOp(const Packet& a) const { return internal::pcos(a); } }; @@ -694,7 +725,7 @@ struct functor_traits > */ template struct scalar_sin_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_sin_op) - inline const Scalar operator() (const Scalar& a) const { return sin(a); } + inline const Scalar operator() (const Scalar& a) const { return internal::sin(a); } typedef typename packet_traits::type Packet; inline Packet packetOp(const Packet& a) const { return internal::psin(a); } }; @@ -714,7 +745,7 @@ struct functor_traits > */ template struct scalar_tan_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_tan_op) - inline const Scalar operator() (const Scalar& a) const { return tan(a); } + inline const Scalar operator() (const Scalar& a) const { return internal::tan(a); } typedef typename packet_traits::type Packet; inline Packet packetOp(const Packet& a) const { return internal::ptan(a); } }; @@ -733,7 +764,7 @@ struct functor_traits > */ template struct scalar_acos_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_acos_op) - inline const Scalar operator() (const Scalar& a) const { return acos(a); } + inline const Scalar operator() (const Scalar& a) const { return internal::acos(a); } typedef typename packet_traits::type Packet; inline Packet packetOp(const Packet& a) const { return internal::pacos(a); } }; @@ -752,7 +783,7 @@ struct functor_traits > */ template struct scalar_asin_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_asin_op) - inline const Scalar operator() (const Scalar& a) const { return asin(a); } + inline const Scalar operator() (const Scalar& a) const { return internal::asin(a); } typedef typename packet_traits::type Packet; inline Packet packetOp(const Packet& a) const { return internal::pasin(a); } }; @@ -781,6 +812,20 @@ template struct functor_traits > { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; }; +/** \internal + * \brief Template functor to compute the quotient between a scalar and array entries. + * \sa class CwiseUnaryOp, Cwise::inverse() + */ +template +struct scalar_inverse_mult_op { + scalar_inverse_mult_op(const Scalar& other) : m_other(other) {} + inline Scalar operator() (const Scalar& a) const { return m_other / a; } + template + inline const Packet packetOp(const Packet& a) const + { return internal::pdiv(pset1(m_other),a); } + Scalar m_other; +}; + /** \internal * \brief Template functor to compute the inverse of a scalar * \sa class CwiseUnaryOp, Cwise::inverse() @@ -939,4 +984,6 @@ struct functor_traits > } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_FUNCTORS_H diff --git a/extern/Eigen3/Eigen/src/Core/Fuzzy.h b/extern/Eigen3/Eigen/src/Core/Fuzzy.h index d266eed0ac6..d74edcfdb9d 100644 --- a/extern/Eigen3/Eigen/src/Core/Fuzzy.h +++ b/extern/Eigen3/Eigen/src/Core/Fuzzy.h @@ -4,28 +4,15 @@ // Copyright (C) 2006-2008 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_FUZZY_H #define EIGEN_FUZZY_H +namespace Eigen { + namespace internal { @@ -35,8 +22,8 @@ struct isApprox_selector static bool run(const Derived& x, const OtherDerived& y, typename Derived::RealScalar prec) { using std::min; - const typename internal::nested::type nested(x); - const typename internal::nested::type otherNested(y); + typename internal::nested::type nested(x); + typename internal::nested::type otherNested(y); return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * (min)(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); } }; @@ -158,4 +145,6 @@ bool DenseBase::isMuchSmallerThan( return internal::isMuchSmallerThan_object_selector::run(derived(), other.derived(), prec); } +} // end namespace Eigen + #endif // EIGEN_FUZZY_H diff --git a/extern/Eigen3/Eigen/src/Core/GeneralProduct.h b/extern/Eigen3/Eigen/src/Core/GeneralProduct.h new file mode 100644 index 00000000000..bfc2a67b12f --- /dev/null +++ b/extern/Eigen3/Eigen/src/Core/GeneralProduct.h @@ -0,0 +1,613 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2008-2011 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_GENERAL_PRODUCT_H +#define EIGEN_GENERAL_PRODUCT_H + +namespace Eigen { + +/** \class GeneralProduct + * \ingroup Core_Module + * + * \brief Expression of the product of two general matrices or vectors + * + * \param LhsNested the type used to store the left-hand side + * \param RhsNested the type used to store the right-hand side + * \param ProductMode the type of the product + * + * This class represents an expression of the product of two general matrices. + * We call a general matrix, a dense matrix with full storage. For instance, + * This excludes triangular, selfadjoint, and sparse matrices. + * It is the return type of the operator* between general matrices. Its template + * arguments are determined automatically by ProductReturnType. Therefore, + * GeneralProduct should never be used direclty. To determine the result type of a + * function which involves a matrix product, use ProductReturnType::Type. + * + * \sa ProductReturnType, MatrixBase::operator*(const MatrixBase&) + */ +template::value> +class GeneralProduct; + +enum { + Large = 2, + Small = 3 +}; + +namespace internal { + +template struct product_type_selector; + +template struct product_size_category +{ + enum { is_large = MaxSize == Dynamic || + Size >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD, + value = is_large ? Large + : Size == 1 ? 1 + : Small + }; +}; + +template struct product_type +{ + typedef typename remove_all::type _Lhs; + typedef typename remove_all::type _Rhs; + enum { + MaxRows = _Lhs::MaxRowsAtCompileTime, + Rows = _Lhs::RowsAtCompileTime, + MaxCols = _Rhs::MaxColsAtCompileTime, + Cols = _Rhs::ColsAtCompileTime, + MaxDepth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::MaxColsAtCompileTime, + _Rhs::MaxRowsAtCompileTime), + Depth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::ColsAtCompileTime, + _Rhs::RowsAtCompileTime), + LargeThreshold = EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD + }; + + // the splitting into different lines of code here, introducing the _select enums and the typedef below, + // is to work around an internal compiler error with gcc 4.1 and 4.2. +private: + enum { + rows_select = product_size_category::value, + cols_select = product_size_category::value, + depth_select = product_size_category::value + }; + typedef product_type_selector selector; + +public: + enum { + value = selector::ret + }; +#ifdef EIGEN_DEBUG_PRODUCT + static void debug() + { + EIGEN_DEBUG_VAR(Rows); + EIGEN_DEBUG_VAR(Cols); + EIGEN_DEBUG_VAR(Depth); + EIGEN_DEBUG_VAR(rows_select); + EIGEN_DEBUG_VAR(cols_select); + EIGEN_DEBUG_VAR(depth_select); + EIGEN_DEBUG_VAR(value); + } +#endif +}; + + +/* The following allows to select the kind of product at compile time + * based on the three dimensions of the product. + * This is a compile time mapping from {1,Small,Large}^3 -> {product types} */ +// FIXME I'm not sure the current mapping is the ideal one. +template struct product_type_selector { enum { ret = OuterProduct }; }; +template struct product_type_selector<1, 1, Depth> { enum { ret = InnerProduct }; }; +template<> struct product_type_selector<1, 1, 1> { enum { ret = InnerProduct }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector<1, Small,Small> { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; +template<> struct product_type_selector<1, Large,Small> { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector<1, Large,Large> { enum { ret = GemvProduct }; }; +template<> struct product_type_selector<1, Small,Large> { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = GemvProduct }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; + +} // end namespace internal + +/** \class ProductReturnType + * \ingroup Core_Module + * + * \brief Helper class to get the correct and optimized returned type of operator* + * + * \param Lhs the type of the left-hand side + * \param Rhs the type of the right-hand side + * \param ProductMode the type of the product (determined automatically by internal::product_mode) + * + * This class defines the typename Type representing the optimized product expression + * between two matrix expressions. In practice, using ProductReturnType::Type + * is the recommended way to define the result type of a function returning an expression + * which involve a matrix product. The class Product should never be + * used directly. + * + * \sa class Product, MatrixBase::operator*(const MatrixBase&) + */ +template +struct ProductReturnType +{ + // TODO use the nested type to reduce instanciations ???? +// typedef typename internal::nested::type LhsNested; +// typedef typename internal::nested::type RhsNested; + + typedef GeneralProduct Type; +}; + +template +struct ProductReturnType +{ + typedef typename internal::nested::type >::type LhsNested; + typedef typename internal::nested::type >::type RhsNested; + typedef CoeffBasedProduct Type; +}; + +template +struct ProductReturnType +{ + typedef typename internal::nested::type >::type LhsNested; + typedef typename internal::nested::type >::type RhsNested; + typedef CoeffBasedProduct Type; +}; + +// this is a workaround for sun CC +template +struct LazyProductReturnType : public ProductReturnType +{}; + +/*********************************************************************** +* Implementation of Inner Vector Vector Product +***********************************************************************/ + +// FIXME : maybe the "inner product" could return a Scalar +// instead of a 1x1 matrix ?? +// Pro: more natural for the user +// Cons: this could be a problem if in a meta unrolled algorithm a matrix-matrix +// product ends up to a row-vector times col-vector product... To tackle this use +// case, we could have a specialization for Block with: operator=(Scalar x); + +namespace internal { + +template +struct traits > + : traits::ReturnType,1,1> > +{}; + +} + +template +class GeneralProduct + : internal::no_assignment_operator, + public Matrix::ReturnType,1,1> +{ + typedef Matrix::ReturnType,1,1> Base; + public: + GeneralProduct(const Lhs& lhs, const Rhs& rhs) + { + EIGEN_STATIC_ASSERT((internal::is_same::value), + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + + Base::coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum(); + } + + /** Convertion to scalar */ + operator const typename Base::Scalar() const { + return Base::coeff(0,0); + } +}; + +/*********************************************************************** +* Implementation of Outer Vector Vector Product +***********************************************************************/ + +namespace internal { +template struct outer_product_selector; + +template +struct traits > + : traits, Lhs, Rhs> > +{}; + +} + +template +class GeneralProduct + : public ProductBase, Lhs, Rhs> +{ + public: + EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) + + GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) + { + EIGEN_STATIC_ASSERT((internal::is_same::value), + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + } + + template void scaleAndAddTo(Dest& dest, Scalar alpha) const + { + internal::outer_product_selector<(int(Dest::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(*this, dest, alpha); + } +}; + +namespace internal { + +template<> struct outer_product_selector { + template + static EIGEN_DONT_INLINE void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) { + typedef typename Dest::Index Index; + // FIXME make sure lhs is sequentially stored + // FIXME not very good if rhs is real and lhs complex while alpha is real too + const Index cols = dest.cols(); + for (Index j=0; j struct outer_product_selector { + template + static EIGEN_DONT_INLINE void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) { + typedef typename Dest::Index Index; + // FIXME make sure rhs is sequentially stored + // FIXME not very good if lhs is real and rhs complex while alpha is real too + const Index rows = dest.rows(); + for (Index i=0; i call fast BLAS-like colmajor routine + * 2 - the matrix is row-major, BLAS compatible and N is large => call fast BLAS-like rowmajor routine + * 3 - all other cases are handled using a simple loop along the outer-storage direction. + * Therefore we need a lower level meta selector. + * Furthermore, if the matrix is the rhs, then the product has to be transposed. + */ +namespace internal { + +template +struct traits > + : traits, Lhs, Rhs> > +{}; + +template +struct gemv_selector; + +} // end namespace internal + +template +class GeneralProduct + : public ProductBase, Lhs, Rhs> +{ + public: + EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) + + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + + GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) + { +// EIGEN_STATIC_ASSERT((internal::is_same::value), +// YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + } + + enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; + typedef typename internal::conditional::type MatrixType; + + template void scaleAndAddTo(Dest& dst, Scalar alpha) const + { + eigen_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols()); + internal::gemv_selector::HasUsableDirectAccess)>::run(*this, dst, alpha); + } +}; + +namespace internal { + +// The vector is on the left => transposition +template +struct gemv_selector +{ + template + static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) + { + Transpose destT(dest); + enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; + gemv_selector + ::run(GeneralProduct,Transpose, GemvProduct> + (prod.rhs().transpose(), prod.lhs().transpose()), destT, alpha); + } +}; + +template struct gemv_static_vector_if; + +template +struct gemv_static_vector_if +{ + EIGEN_STRONG_INLINE Scalar* data() { eigen_internal_assert(false && "should never be called"); return 0; } +}; + +template +struct gemv_static_vector_if +{ + EIGEN_STRONG_INLINE Scalar* data() { return 0; } +}; + +template +struct gemv_static_vector_if +{ + #if EIGEN_ALIGN_STATICALLY + internal::plain_array m_data; + EIGEN_STRONG_INLINE Scalar* data() { return m_data.array; } + #else + // Some architectures cannot align on the stack, + // => let's manually enforce alignment by allocating more data and return the address of the first aligned element. + enum { + ForceAlignment = internal::packet_traits::Vectorizable, + PacketSize = internal::packet_traits::size + }; + internal::plain_array m_data; + EIGEN_STRONG_INLINE Scalar* data() { + return ForceAlignment + ? reinterpret_cast((reinterpret_cast(m_data.array) & ~(size_t(15))) + 16) + : m_data.array; + } + #endif +}; + +template<> struct gemv_selector +{ + template + static inline void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) + { + typedef typename ProductType::Index Index; + typedef typename ProductType::LhsScalar LhsScalar; + typedef typename ProductType::RhsScalar RhsScalar; + typedef typename ProductType::Scalar ResScalar; + typedef typename ProductType::RealScalar RealScalar; + typedef typename ProductType::ActualLhsType ActualLhsType; + typedef typename ProductType::ActualRhsType ActualRhsType; + typedef typename ProductType::LhsBlasTraits LhsBlasTraits; + typedef typename ProductType::RhsBlasTraits RhsBlasTraits; + typedef Map, Aligned> MappedDest; + + ActualLhsType actualLhs = LhsBlasTraits::extract(prod.lhs()); + ActualRhsType actualRhs = RhsBlasTraits::extract(prod.rhs()); + + ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) + * RhsBlasTraits::extractScalarFactor(prod.rhs()); + + enum { + // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 + // on, the other hand it is good for the cache to pack the vector anyways... + EvalToDestAtCompileTime = Dest::InnerStrideAtCompileTime==1, + ComplexByReal = (NumTraits::IsComplex) && (!NumTraits::IsComplex), + MightCannotUseDest = (Dest::InnerStrideAtCompileTime!=1) || ComplexByReal + }; + + gemv_static_vector_if static_dest; + + bool alphaIsCompatible = (!ComplexByReal) || (imag(actualAlpha)==RealScalar(0)); + bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible; + + RhsScalar compatibleAlpha = get_factor::run(actualAlpha); + + ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(), + evalToDest ? dest.data() : static_dest.data()); + + if(!evalToDest) + { + #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN + int size = dest.size(); + EIGEN_DENSE_STORAGE_CTOR_PLUGIN + #endif + if(!alphaIsCompatible) + { + MappedDest(actualDestPtr, dest.size()).setZero(); + compatibleAlpha = RhsScalar(1); + } + else + MappedDest(actualDestPtr, dest.size()) = dest; + } + + general_matrix_vector_product + ::run( + actualLhs.rows(), actualLhs.cols(), + actualLhs.data(), actualLhs.outerStride(), + actualRhs.data(), actualRhs.innerStride(), + actualDestPtr, 1, + compatibleAlpha); + + if (!evalToDest) + { + if(!alphaIsCompatible) + dest += actualAlpha * MappedDest(actualDestPtr, dest.size()); + else + dest = MappedDest(actualDestPtr, dest.size()); + } + } +}; + +template<> struct gemv_selector +{ + template + static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) + { + typedef typename ProductType::LhsScalar LhsScalar; + typedef typename ProductType::RhsScalar RhsScalar; + typedef typename ProductType::Scalar ResScalar; + typedef typename ProductType::Index Index; + typedef typename ProductType::ActualLhsType ActualLhsType; + typedef typename ProductType::ActualRhsType ActualRhsType; + typedef typename ProductType::_ActualRhsType _ActualRhsType; + typedef typename ProductType::LhsBlasTraits LhsBlasTraits; + typedef typename ProductType::RhsBlasTraits RhsBlasTraits; + + typename add_const::type actualLhs = LhsBlasTraits::extract(prod.lhs()); + typename add_const::type actualRhs = RhsBlasTraits::extract(prod.rhs()); + + ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) + * RhsBlasTraits::extractScalarFactor(prod.rhs()); + + enum { + // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 + // on, the other hand it is good for the cache to pack the vector anyways... + DirectlyUseRhs = _ActualRhsType::InnerStrideAtCompileTime==1 + }; + + gemv_static_vector_if static_rhs; + + ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,actualRhs.size(), + DirectlyUseRhs ? const_cast(actualRhs.data()) : static_rhs.data()); + + if(!DirectlyUseRhs) + { + #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN + int size = actualRhs.size(); + EIGEN_DENSE_STORAGE_CTOR_PLUGIN + #endif + Map(actualRhsPtr, actualRhs.size()) = actualRhs; + } + + general_matrix_vector_product + ::run( + actualLhs.rows(), actualLhs.cols(), + actualLhs.data(), actualLhs.outerStride(), + actualRhsPtr, 1, + dest.data(), dest.innerStride(), + actualAlpha); + } +}; + +template<> struct gemv_selector +{ + template + static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) + { + typedef typename Dest::Index Index; + // TODO makes sure dest is sequentially stored in memory, otherwise use a temp + const Index size = prod.rhs().rows(); + for(Index k=0; k struct gemv_selector +{ + template + static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) + { + typedef typename Dest::Index Index; + // TODO makes sure rhs is sequentially stored in memory, otherwise use a temp + const Index rows = prod.rows(); + for(Index i=0; i +template +inline const typename ProductReturnType::Type +MatrixBase::operator*(const MatrixBase &other) const +{ + // A note regarding the function declaration: In MSVC, this function will sometimes + // not be inlined since DenseStorage is an unwindable object for dynamic + // matrices and product types are holding a member to store the result. + // Thus it does not help tagging this function with EIGEN_STRONG_INLINE. + enum { + ProductIsValid = Derived::ColsAtCompileTime==Dynamic + || OtherDerived::RowsAtCompileTime==Dynamic + || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime), + AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime, + SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived) + }; + // note to the lost user: + // * for a dot product use: v1.dot(v2) + // * for a coeff-wise product use: v1.cwiseProduct(v2) + EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), + INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) + EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), + INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) + EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) +#ifdef EIGEN_DEBUG_PRODUCT + internal::product_type::debug(); +#endif + return typename ProductReturnType::Type(derived(), other.derived()); +} + +/** \returns an expression of the matrix product of \c *this and \a other without implicit evaluation. + * + * The returned product will behave like any other expressions: the coefficients of the product will be + * computed once at a time as requested. This might be useful in some extremely rare cases when only + * a small and no coherent fraction of the result's coefficients have to be computed. + * + * \warning This version of the matrix product can be much much slower. So use it only if you know + * what you are doing and that you measured a true speed improvement. + * + * \sa operator*(const MatrixBase&) + */ +template +template +const typename LazyProductReturnType::Type +MatrixBase::lazyProduct(const MatrixBase &other) const +{ + enum { + ProductIsValid = Derived::ColsAtCompileTime==Dynamic + || OtherDerived::RowsAtCompileTime==Dynamic + || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime), + AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime, + SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived) + }; + // note to the lost user: + // * for a dot product use: v1.dot(v2) + // * for a coeff-wise product use: v1.cwiseProduct(v2) + EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), + INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) + EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), + INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) + EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) + + return typename LazyProductReturnType::Type(derived(), other.derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_PRODUCT_H diff --git a/extern/Eigen3/Eigen/src/Core/GenericPacketMath.h b/extern/Eigen3/Eigen/src/Core/GenericPacketMath.h index 8ed83532712..858fb243ec8 100644 --- a/extern/Eigen3/Eigen/src/Core/GenericPacketMath.h +++ b/extern/Eigen3/Eigen/src/Core/GenericPacketMath.h @@ -4,28 +4,15 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_GENERIC_PACKET_MATH_H #define EIGEN_GENERIC_PACKET_MATH_H +namespace Eigen { + namespace internal { /** \internal @@ -312,7 +299,7 @@ template struct palign_impl { // by default data are aligned, so there is nothing to be done :) - inline static void run(PacketType&, const PacketType&) {} + static inline void run(PacketType&, const PacketType&) {} }; /** \internal update \a first using the concatenation of the \a Offset last elements @@ -335,5 +322,7 @@ template<> inline std::complex pmul(const std::complex& a, const } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_GENERIC_PACKET_MATH_H diff --git a/extern/Eigen3/Eigen/src/Core/GlobalFunctions.h b/extern/Eigen3/Eigen/src/Core/GlobalFunctions.h index 144145a955c..e63726c4735 100644 --- a/extern/Eigen3/Eigen/src/Core/GlobalFunctions.h +++ b/extern/Eigen3/Eigen/src/Core/GlobalFunctions.h @@ -4,24 +4,9 @@ // Copyright (C) 2010 Gael Guennebaud // Copyright (C) 2010 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_GLOBAL_FUNCTIONS_H #define EIGEN_GLOBAL_FUNCTIONS_H @@ -66,13 +51,36 @@ namespace std template inline const Eigen::CwiseUnaryOp, const Derived> - pow(const Eigen::ArrayBase& x, const typename Derived::Scalar& exponent) { \ - return x.derived().pow(exponent); \ + pow(const Eigen::ArrayBase& x, const typename Derived::Scalar& exponent) { + return x.derived().pow(exponent); + } + + template + inline const Eigen::CwiseBinaryOp, const Derived, const Derived> + pow(const Eigen::ArrayBase& x, const Eigen::ArrayBase& exponents) + { + return Eigen::CwiseBinaryOp, const Derived, const Derived>( + x.derived(), + exponents.derived() + ); } } namespace Eigen { + /** + * \brief Component-wise division of a scalar by array elements. + **/ + template + inline const Eigen::CwiseUnaryOp, const Derived> + operator/(typename Derived::Scalar s, const Eigen::ArrayBase& a) + { + return Eigen::CwiseUnaryOp, const Derived>( + a.derived(), + Eigen::internal::scalar_inverse_mult_op(s) + ); + } + namespace internal { EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(real,scalar_real_op) diff --git a/extern/Eigen3/Eigen/src/Core/IO.h b/extern/Eigen3/Eigen/src/Core/IO.h index f3cfcdbf4a3..cc8e18a0076 100644 --- a/extern/Eigen3/Eigen/src/Core/IO.h +++ b/extern/Eigen3/Eigen/src/Core/IO.h @@ -4,28 +4,15 @@ // Copyright (C) 2006-2008 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_IO_H #define EIGEN_IO_H +namespace Eigen { + enum { DontAlignCols = 1 }; enum { StreamPrecision = -1, FullPrecision = -2 }; @@ -171,7 +158,7 @@ std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& return s; } - const typename Derived::Nested m = _m; + typename Derived::Nested m = _m; typedef typename Derived::Scalar Scalar; typedef typename Derived::Index Index; @@ -257,4 +244,6 @@ std::ostream & operator << return internal::print_matrix(s, m.eval(), EIGEN_DEFAULT_IO_FORMAT); } +} // end namespace Eigen + #endif // EIGEN_IO_H diff --git a/extern/Eigen3/Eigen/src/Core/Map.h b/extern/Eigen3/Eigen/src/Core/Map.h index 2bf80b3af3d..15a19226e29 100644 --- a/extern/Eigen3/Eigen/src/Core/Map.h +++ b/extern/Eigen3/Eigen/src/Core/Map.h @@ -4,28 +4,15 @@ // Copyright (C) 2007-2010 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MAP_H #define EIGEN_MAP_H +namespace Eigen { + /** \class Map * \ingroup Core_Module * @@ -200,4 +187,6 @@ inline Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> this->_set_noalias(Eigen::Map(data)); } +} // end namespace Eigen + #endif // EIGEN_MAP_H diff --git a/extern/Eigen3/Eigen/src/Core/MapBase.h b/extern/Eigen3/Eigen/src/Core/MapBase.h index 9426e2d24dd..a388d61ea92 100644 --- a/extern/Eigen3/Eigen/src/Core/MapBase.h +++ b/extern/Eigen3/Eigen/src/Core/MapBase.h @@ -4,24 +4,9 @@ // Copyright (C) 2007-2010 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MAPBASE_H #define EIGEN_MAPBASE_H @@ -30,6 +15,7 @@ EIGEN_STATIC_ASSERT((int(internal::traits::Flags) & LinearAccessBit) || Derived::IsVectorAtCompileTime, \ YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT) +namespace Eigen { /** \class MapBase * \ingroup Core_Module @@ -251,5 +237,6 @@ template class MapBase using Base::Base::operator=; }; +} // end namespace Eigen #endif // EIGEN_MAPBASE_H diff --git a/extern/Eigen3/Eigen/src/Core/MathFunctions.h b/extern/Eigen3/Eigen/src/Core/MathFunctions.h index 2b454db21e9..05e913f2fec 100644 --- a/extern/Eigen3/Eigen/src/Core/MathFunctions.h +++ b/extern/Eigen3/Eigen/src/Core/MathFunctions.h @@ -3,28 +3,15 @@ // // Copyright (C) 2006-2010 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MATHFUNCTIONS_H #define EIGEN_MATHFUNCTIONS_H +namespace Eigen { + namespace internal { /** \internal \struct global_math_functions_filtering_base @@ -309,8 +296,7 @@ struct abs2_impl > { static inline RealScalar run(const std::complex& x) { - using std::norm; - return norm(x); + return real(x)*real(x) + imag(x)*imag(x); } }; @@ -553,7 +539,7 @@ struct pow_default_impl { static inline Scalar run(Scalar x, Scalar y) { - Scalar res = 1; + Scalar res(1); eigen_assert(!NumTraits::IsSigned || y >= 0); if(y & 1) res *= x; y >>= 1; @@ -838,6 +824,19 @@ template<> struct scalar_fuzzy_impl }; +/**************************************************************************** +* Special functions * +****************************************************************************/ + +// std::isfinite is non standard, so let's define our own version, +// even though it is not very efficient. +template bool (isfinite)(const T& x) +{ + return x::highest() && x>NumTraits::lowest(); +} + } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_MATHFUNCTIONS_H diff --git a/extern/Eigen3/Eigen/src/Core/Matrix.h b/extern/Eigen3/Eigen/src/Core/Matrix.h index 982c9256af0..99160b591b0 100644 --- a/extern/Eigen3/Eigen/src/Core/Matrix.h +++ b/extern/Eigen3/Eigen/src/Core/Matrix.h @@ -4,28 +4,15 @@ // Copyright (C) 2006-2010 Benoit Jacob // Copyright (C) 2008-2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MATRIX_H #define EIGEN_MATRIX_H +namespace Eigen { + /** \class Matrix * \ingroup Core_Module * @@ -411,25 +398,8 @@ EIGEN_MAKE_TYPEDEFS_ALL_SIZES(std::complex, cd) #undef EIGEN_MAKE_TYPEDEFS_ALL_SIZES #undef EIGEN_MAKE_TYPEDEFS +#undef EIGEN_MAKE_FIXED_TYPEDEFS -#undef EIGEN_MAKE_TYPEDEFS_LARGE - -#define EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, SizeSuffix) \ -using Eigen::Matrix##SizeSuffix##TypeSuffix; \ -using Eigen::Vector##SizeSuffix##TypeSuffix; \ -using Eigen::RowVector##SizeSuffix##TypeSuffix; - -#define EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(TypeSuffix) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 2) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 3) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 4) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, X) \ - -#define EIGEN_USING_MATRIX_TYPEDEFS \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(i) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(f) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(d) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(cf) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(cd) +} // end namespace Eigen #endif // EIGEN_MATRIX_H diff --git a/extern/Eigen3/Eigen/src/Core/MatrixBase.h b/extern/Eigen3/Eigen/src/Core/MatrixBase.h index 62877bce09e..c1e0ed132cc 100644 --- a/extern/Eigen3/Eigen/src/Core/MatrixBase.h +++ b/extern/Eigen3/Eigen/src/Core/MatrixBase.h @@ -4,28 +4,15 @@ // Copyright (C) 2006-2009 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MATRIXBASE_H #define EIGEN_MATRIXBASE_H +namespace Eigen { + /** \class MatrixBase * \ingroup Core_Module * @@ -250,8 +237,7 @@ template class MatrixBase // huuuge hack. make Eigen2's matrix.part() work in eigen3. Problem: Diagonal is now a class template instead // of an integer constant. Solution: overload the part() method template wrt template parameters list. - // Note: replacing next line by "template class U>" produces a mysterious error C2082 in MSVC. - template class U> + template class U> const DiagonalWrapper part() const { return diagonal().asDiagonal(); } #endif // EIGEN2_SUPPORT @@ -331,7 +317,7 @@ template class MatrixBase /** \returns an \link ArrayBase Array \endlink expression of this matrix * \sa ArrayBase::matrix() */ ArrayWrapper array() { return derived(); } - const ArrayWrapper array() const { return derived(); } + const ArrayWrapper array() const { return derived(); } /////////// LU module /////////// @@ -466,6 +452,8 @@ template class MatrixBase const MatrixFunctionReturnValue sinh() const; const MatrixFunctionReturnValue cos() const; const MatrixFunctionReturnValue sin() const; + const MatrixSquareRootReturnValue sqrt() const; + const MatrixLogarithmReturnValue log() const; #ifdef EIGEN2_SUPPORT template @@ -512,10 +500,12 @@ template class MatrixBase protected: // mixing arrays and matrices is not legal template Derived& operator+=(const ArrayBase& ) - {EIGEN_STATIC_ASSERT(sizeof(typename OtherDerived::Scalar)==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES);} + {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} // mixing arrays and matrices is not legal template Derived& operator-=(const ArrayBase& ) - {EIGEN_STATIC_ASSERT(sizeof(typename OtherDerived::Scalar)==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES);} + {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} }; +} // end namespace Eigen + #endif // EIGEN_MATRIXBASE_H diff --git a/extern/Eigen3/Eigen/src/Core/NestByValue.h b/extern/Eigen3/Eigen/src/Core/NestByValue.h index a6104d2a426..a893b1761b5 100644 --- a/extern/Eigen3/Eigen/src/Core/NestByValue.h +++ b/extern/Eigen3/Eigen/src/Core/NestByValue.h @@ -4,28 +4,15 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_NESTBYVALUE_H #define EIGEN_NESTBYVALUE_H +namespace Eigen { + /** \class NestByValue * \ingroup Core_Module * @@ -119,4 +106,6 @@ DenseBase::nestByValue() const return NestByValue(derived()); } +} // end namespace Eigen + #endif // EIGEN_NESTBYVALUE_H diff --git a/extern/Eigen3/Eigen/src/Core/NoAlias.h b/extern/Eigen3/Eigen/src/Core/NoAlias.h index da64affcf9a..ecb3fa2850e 100644 --- a/extern/Eigen3/Eigen/src/Core/NoAlias.h +++ b/extern/Eigen3/Eigen/src/Core/NoAlias.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_NOALIAS_H #define EIGEN_NOALIAS_H +namespace Eigen { + /** \class NoAlias * \ingroup Core_Module * @@ -133,4 +120,6 @@ NoAlias MatrixBase::noalias() return derived(); } +} // end namespace Eigen + #endif // EIGEN_NOALIAS_H diff --git a/extern/Eigen3/Eigen/src/Core/NumTraits.h b/extern/Eigen3/Eigen/src/Core/NumTraits.h index 73ef05dfe7a..c94ef026b42 100644 --- a/extern/Eigen3/Eigen/src/Core/NumTraits.h +++ b/extern/Eigen3/Eigen/src/Core/NumTraits.h @@ -3,28 +3,15 @@ // // Copyright (C) 2006-2010 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_NUMTRAITS_H #define EIGEN_NUMTRAITS_H +namespace Eigen { + /** \class NumTraits * \ingroup Core_Module * @@ -81,14 +68,14 @@ template struct GenericNumTraits >::type NonInteger; typedef T Nested; - inline static Real epsilon() { return std::numeric_limits::epsilon(); } - inline static Real dummy_precision() + static inline Real epsilon() { return std::numeric_limits::epsilon(); } + static inline Real dummy_precision() { // make sure to override this for floating-point types return Real(0); } - inline static T highest() { return (std::numeric_limits::max)(); } - inline static T lowest() { return IsInteger ? (std::numeric_limits::min)() : (-(std::numeric_limits::max)()); } + static inline T highest() { return (std::numeric_limits::max)(); } + static inline T lowest() { return IsInteger ? (std::numeric_limits::min)() : (-(std::numeric_limits::max)()); } #ifdef EIGEN2_SUPPORT enum { @@ -104,12 +91,12 @@ template struct NumTraits : GenericNumTraits template<> struct NumTraits : GenericNumTraits { - inline static float dummy_precision() { return 1e-5f; } + static inline float dummy_precision() { return 1e-5f; } }; template<> struct NumTraits : GenericNumTraits { - inline static double dummy_precision() { return 1e-12; } + static inline double dummy_precision() { return 1e-12; } }; template<> struct NumTraits @@ -130,8 +117,8 @@ template struct NumTraits > MulCost = 4 * NumTraits::MulCost + 2 * NumTraits::AddCost }; - inline static Real epsilon() { return NumTraits::epsilon(); } - inline static Real dummy_precision() { return NumTraits::dummy_precision(); } + static inline Real epsilon() { return NumTraits::epsilon(); } + static inline Real dummy_precision() { return NumTraits::dummy_precision(); } }; template @@ -155,6 +142,6 @@ struct NumTraits > }; }; - +} // end namespace Eigen #endif // EIGEN_NUMTRAITS_H diff --git a/extern/Eigen3/Eigen/src/Core/PermutationMatrix.h b/extern/Eigen3/Eigen/src/Core/PermutationMatrix.h index a064e053e51..bc29f814205 100644 --- a/extern/Eigen3/Eigen/src/Core/PermutationMatrix.h +++ b/extern/Eigen3/Eigen/src/Core/PermutationMatrix.h @@ -4,28 +4,15 @@ // Copyright (C) 2009 Benoit Jacob // Copyright (C) 2009-2011 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_PERMUTATIONMATRIX_H #define EIGEN_PERMUTATIONMATRIX_H +namespace Eigen { + template class PermutedImpl; /** \class PermutationBase @@ -56,6 +43,8 @@ namespace internal { template struct permut_matrix_product_retval; +template +struct permut_sparsematrix_product_retval; enum PermPermProduct_t {PermPermProduct}; } // end namespace internal @@ -511,7 +500,7 @@ class PermutationWrapper : public PermutationBase MatrixBase::asPermutation() con return derived(); } +} // end namespace Eigen + #endif // EIGEN_PERMUTATIONMATRIX_H diff --git a/extern/Eigen3/Eigen/src/Core/PlainObjectBase.h b/extern/Eigen3/Eigen/src/Core/PlainObjectBase.h index 612254e9da9..71c74309acc 100644 --- a/extern/Eigen3/Eigen/src/Core/PlainObjectBase.h +++ b/extern/Eigen3/Eigen/src/Core/PlainObjectBase.h @@ -4,24 +4,9 @@ // Copyright (C) 2008-2009 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_DENSESTORAGEBASE_H #define EIGEN_DENSESTORAGEBASE_H @@ -32,6 +17,8 @@ # define EIGEN_INITIALIZE_BY_ZERO_IF_THAT_OPTION_IS_ENABLED #endif +namespace Eigen { + namespace internal { template @@ -47,13 +34,13 @@ EIGEN_ALWAYS_INLINE void check_rows_cols_for_overflow(Index rows, Index cols) throw_std_bad_alloc(); } -template (Derived::IsVectorAtCompileTime)> struct conservative_resize_like_impl; +template struct conservative_resize_like_impl; template struct matrix_swap_impl; } // end namespace internal -/** +/** \class PlainObjectBase * \brief %Dense storage base class for matrices and arrays. * * This class can be extended with the help of the plugin mechanism described on the page @@ -61,8 +48,29 @@ template struct m * * \sa \ref TopicClassHierarchy */ +#ifdef EIGEN_PARSED_BY_DOXYGEN +namespace internal { + +// this is a warkaround to doxygen not being able to understand the inheritence logic +// when it is hidden by the dense_xpr_base helper struct. +template struct dense_xpr_base_dispatcher_for_doxygen;// : public MatrixBase {}; +/** This class is just a workaround for Doxygen and it does not not actually exist. */ +template +struct dense_xpr_base_dispatcher_for_doxygen > + : public MatrixBase > {}; +/** This class is just a workaround for Doxygen and it does not not actually exist. */ +template +struct dense_xpr_base_dispatcher_for_doxygen > + : public ArrayBase > {}; + +} // namespace internal + +template +class PlainObjectBase : public internal::dense_xpr_base_dispatcher_for_doxygen +#else template class PlainObjectBase : public internal::dense_xpr_base::type +#endif { public: enum { Options = internal::traits::Options }; @@ -443,68 +451,68 @@ class PlainObjectBase : public internal::dense_xpr_base::type * \see class Map */ //@{ - inline static ConstMapType Map(const Scalar* data) + static inline ConstMapType Map(const Scalar* data) { return ConstMapType(data); } - inline static MapType Map(Scalar* data) + static inline MapType Map(Scalar* data) { return MapType(data); } - inline static ConstMapType Map(const Scalar* data, Index size) + static inline ConstMapType Map(const Scalar* data, Index size) { return ConstMapType(data, size); } - inline static MapType Map(Scalar* data, Index size) + static inline MapType Map(Scalar* data, Index size) { return MapType(data, size); } - inline static ConstMapType Map(const Scalar* data, Index rows, Index cols) + static inline ConstMapType Map(const Scalar* data, Index rows, Index cols) { return ConstMapType(data, rows, cols); } - inline static MapType Map(Scalar* data, Index rows, Index cols) + static inline MapType Map(Scalar* data, Index rows, Index cols) { return MapType(data, rows, cols); } - inline static ConstAlignedMapType MapAligned(const Scalar* data) + static inline ConstAlignedMapType MapAligned(const Scalar* data) { return ConstAlignedMapType(data); } - inline static AlignedMapType MapAligned(Scalar* data) + static inline AlignedMapType MapAligned(Scalar* data) { return AlignedMapType(data); } - inline static ConstAlignedMapType MapAligned(const Scalar* data, Index size) + static inline ConstAlignedMapType MapAligned(const Scalar* data, Index size) { return ConstAlignedMapType(data, size); } - inline static AlignedMapType MapAligned(Scalar* data, Index size) + static inline AlignedMapType MapAligned(Scalar* data, Index size) { return AlignedMapType(data, size); } - inline static ConstAlignedMapType MapAligned(const Scalar* data, Index rows, Index cols) + static inline ConstAlignedMapType MapAligned(const Scalar* data, Index rows, Index cols) { return ConstAlignedMapType(data, rows, cols); } - inline static AlignedMapType MapAligned(Scalar* data, Index rows, Index cols) + static inline AlignedMapType MapAligned(Scalar* data, Index rows, Index cols) { return AlignedMapType(data, rows, cols); } template - inline static typename StridedConstMapType >::type Map(const Scalar* data, const Stride& stride) + static inline typename StridedConstMapType >::type Map(const Scalar* data, const Stride& stride) { return typename StridedConstMapType >::type(data, stride); } template - inline static typename StridedMapType >::type Map(Scalar* data, const Stride& stride) + static inline typename StridedMapType >::type Map(Scalar* data, const Stride& stride) { return typename StridedMapType >::type(data, stride); } template - inline static typename StridedConstMapType >::type Map(const Scalar* data, Index size, const Stride& stride) + static inline typename StridedConstMapType >::type Map(const Scalar* data, Index size, const Stride& stride) { return typename StridedConstMapType >::type(data, size, stride); } template - inline static typename StridedMapType >::type Map(Scalar* data, Index size, const Stride& stride) + static inline typename StridedMapType >::type Map(Scalar* data, Index size, const Stride& stride) { return typename StridedMapType >::type(data, size, stride); } template - inline static typename StridedConstMapType >::type Map(const Scalar* data, Index rows, Index cols, const Stride& stride) + static inline typename StridedConstMapType >::type Map(const Scalar* data, Index rows, Index cols, const Stride& stride) { return typename StridedConstMapType >::type(data, rows, cols, stride); } template - inline static typename StridedMapType >::type Map(Scalar* data, Index rows, Index cols, const Stride& stride) + static inline typename StridedMapType >::type Map(Scalar* data, Index rows, Index cols, const Stride& stride) { return typename StridedMapType >::type(data, rows, cols, stride); } template - inline static typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, const Stride& stride) + static inline typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, const Stride& stride) { return typename StridedConstAlignedMapType >::type(data, stride); } template - inline static typename StridedAlignedMapType >::type MapAligned(Scalar* data, const Stride& stride) + static inline typename StridedAlignedMapType >::type MapAligned(Scalar* data, const Stride& stride) { return typename StridedAlignedMapType >::type(data, stride); } template - inline static typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, Index size, const Stride& stride) + static inline typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, Index size, const Stride& stride) { return typename StridedConstAlignedMapType >::type(data, size, stride); } template - inline static typename StridedAlignedMapType >::type MapAligned(Scalar* data, Index size, const Stride& stride) + static inline typename StridedAlignedMapType >::type MapAligned(Scalar* data, Index size, const Stride& stride) { return typename StridedAlignedMapType >::type(data, size, stride); } template - inline static typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, Index rows, Index cols, const Stride& stride) + static inline typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, Index rows, Index cols, const Stride& stride) { return typename StridedConstAlignedMapType >::type(data, rows, cols, stride); } template - inline static typename StridedAlignedMapType >::type MapAligned(Scalar* data, Index rows, Index cols, const Stride& stride) + static inline typename StridedAlignedMapType >::type MapAligned(Scalar* data, Index rows, Index cols, const Stride& stride) { return typename StridedAlignedMapType >::type(data, rows, cols, stride); } //@} @@ -594,6 +602,9 @@ class PlainObjectBase : public internal::dense_xpr_base::type template EIGEN_STRONG_INLINE void _init2(Index rows, Index cols, typename internal::enable_if::type* = 0) { + EIGEN_STATIC_ASSERT(bool(NumTraits::IsInteger) && + bool(NumTraits::IsInteger), + FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED) eigen_assert(rows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows) && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols)); internal::check_rows_cols_for_overflow(rows, cols); @@ -623,7 +634,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type public: #ifndef EIGEN_PARSED_BY_DOXYGEN - EIGEN_STRONG_INLINE static void _check_template_params() + static EIGEN_STRONG_INLINE void _check_template_params() { EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor) && EIGEN_IMPLIES(MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1, (Options&RowMajor)==0) @@ -751,4 +762,6 @@ struct matrix_swap_impl } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_DENSESTORAGEBASE_H diff --git a/extern/Eigen3/Eigen/src/Core/Product.h b/extern/Eigen3/Eigen/src/Core/Product.h index e2035b242b1..30aa8943b4c 100644 --- a/extern/Eigen3/Eigen/src/Core/Product.h +++ b/extern/Eigen3/Eigen/src/Core/Product.h @@ -1,625 +1,98 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2006-2008 Benoit Jacob -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2008-2011 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_PRODUCT_H #define EIGEN_PRODUCT_H -/** \class GeneralProduct +template class Product; +template class ProductImpl; + +/** \class Product * \ingroup Core_Module * - * \brief Expression of the product of two general matrices or vectors + * \brief Expression of the product of two arbitrary matrices or vectors * - * \param LhsNested the type used to store the left-hand side - * \param RhsNested the type used to store the right-hand side - * \param ProductMode the type of the product + * \param Lhs the type of the left-hand side expression + * \param Rhs the type of the right-hand side expression * - * This class represents an expression of the product of two general matrices. - * We call a general matrix, a dense matrix with full storage. For instance, - * This excludes triangular, selfadjoint, and sparse matrices. - * It is the return type of the operator* between general matrices. Its template - * arguments are determined automatically by ProductReturnType. Therefore, - * GeneralProduct should never be used direclty. To determine the result type of a - * function which involves a matrix product, use ProductReturnType::Type. + * This class represents an expression of the product of two arbitrary matrices. * - * \sa ProductReturnType, MatrixBase::operator*(const MatrixBase&) */ -template::value> -class GeneralProduct; - -enum { - Large = 2, - Small = 3 -}; namespace internal { - -template struct product_type_selector; - -template struct product_size_category -{ - enum { is_large = MaxSize == Dynamic || - Size >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD, - value = is_large ? Large - : Size == 1 ? 1 - : Small - }; -}; - -template struct product_type -{ - typedef typename remove_all::type _Lhs; - typedef typename remove_all::type _Rhs; - enum { - MaxRows = _Lhs::MaxRowsAtCompileTime, - Rows = _Lhs::RowsAtCompileTime, - MaxCols = _Rhs::MaxColsAtCompileTime, - Cols = _Rhs::ColsAtCompileTime, - MaxDepth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::MaxColsAtCompileTime, - _Rhs::MaxRowsAtCompileTime), - Depth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::ColsAtCompileTime, - _Rhs::RowsAtCompileTime), - LargeThreshold = EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD - }; - - // the splitting into different lines of code here, introducing the _select enums and the typedef below, - // is to work around an internal compiler error with gcc 4.1 and 4.2. -private: - enum { - rows_select = product_size_category::value, - cols_select = product_size_category::value, - depth_select = product_size_category::value - }; - typedef product_type_selector selector; - -public: +template +struct traits > +{ + typedef MatrixXpr XprKind; + typedef typename remove_all::type LhsCleaned; + typedef typename remove_all::type RhsCleaned; + typedef typename scalar_product_traits::Scalar, typename traits::Scalar>::ReturnType Scalar; + typedef typename promote_storage_type::StorageKind, + typename traits::StorageKind>::ret StorageKind; + typedef typename promote_index_type::Index, + typename traits::Index>::type Index; enum { - value = selector::ret + RowsAtCompileTime = LhsCleaned::RowsAtCompileTime, + ColsAtCompileTime = RhsCleaned::ColsAtCompileTime, + MaxRowsAtCompileTime = LhsCleaned::MaxRowsAtCompileTime, + MaxColsAtCompileTime = RhsCleaned::MaxColsAtCompileTime, + Flags = (MaxRowsAtCompileTime==1 ? RowMajorBit : 0), // TODO should be no storage order + CoeffReadCost = 0 // TODO CoeffReadCost should not be part of the expression traits }; -#ifdef EIGEN_DEBUG_PRODUCT - static void debug() - { - EIGEN_DEBUG_VAR(Rows); - EIGEN_DEBUG_VAR(Cols); - EIGEN_DEBUG_VAR(Depth); - EIGEN_DEBUG_VAR(rows_select); - EIGEN_DEBUG_VAR(cols_select); - EIGEN_DEBUG_VAR(depth_select); - EIGEN_DEBUG_VAR(value); - } -#endif }; - - -/* The following allows to select the kind of product at compile time - * based on the three dimensions of the product. - * This is a compile time mapping from {1,Small,Large}^3 -> {product types} */ -// FIXME I'm not sure the current mapping is the ideal one. -template struct product_type_selector { enum { ret = OuterProduct }; }; -template struct product_type_selector<1, 1, Depth> { enum { ret = InnerProduct }; }; -template<> struct product_type_selector<1, 1, 1> { enum { ret = InnerProduct }; }; -template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; -template<> struct product_type_selector<1, Small,Small> { enum { ret = CoeffBasedProductMode }; }; -template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; -template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; -template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; -template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; -template<> struct product_type_selector<1, Large,Small> { enum { ret = CoeffBasedProductMode }; }; -template<> struct product_type_selector<1, Large,Large> { enum { ret = GemvProduct }; }; -template<> struct product_type_selector<1, Small,Large> { enum { ret = CoeffBasedProductMode }; }; -template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; -template<> struct product_type_selector { enum { ret = GemvProduct }; }; -template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; -template<> struct product_type_selector { enum { ret = GemmProduct }; }; -template<> struct product_type_selector { enum { ret = GemmProduct }; }; -template<> struct product_type_selector { enum { ret = GemmProduct }; }; -template<> struct product_type_selector { enum { ret = GemmProduct }; }; -template<> struct product_type_selector { enum { ret = GemmProduct }; }; -template<> struct product_type_selector { enum { ret = GemmProduct }; }; -template<> struct product_type_selector { enum { ret = GemmProduct }; }; - } // end namespace internal -/** \class ProductReturnType - * \ingroup Core_Module - * - * \brief Helper class to get the correct and optimized returned type of operator* - * - * \param Lhs the type of the left-hand side - * \param Rhs the type of the right-hand side - * \param ProductMode the type of the product (determined automatically by internal::product_mode) - * - * This class defines the typename Type representing the optimized product expression - * between two matrix expressions. In practice, using ProductReturnType::Type - * is the recommended way to define the result type of a function returning an expression - * which involve a matrix product. The class Product should never be - * used directly. - * - * \sa class Product, MatrixBase::operator*(const MatrixBase&) - */ -template -struct ProductReturnType -{ - // TODO use the nested type to reduce instanciations ???? -// typedef typename internal::nested::type LhsNested; -// typedef typename internal::nested::type RhsNested; - - typedef GeneralProduct Type; -}; - -template -struct ProductReturnType -{ - typedef typename internal::nested::type >::type LhsNested; - typedef typename internal::nested::type >::type RhsNested; - typedef CoeffBasedProduct Type; -}; - -template -struct ProductReturnType -{ - typedef typename internal::nested::type >::type LhsNested; - typedef typename internal::nested::type >::type RhsNested; - typedef CoeffBasedProduct Type; -}; - -// this is a workaround for sun CC -template -struct LazyProductReturnType : public ProductReturnType -{}; - -/*********************************************************************** -* Implementation of Inner Vector Vector Product -***********************************************************************/ - -// FIXME : maybe the "inner product" could return a Scalar -// instead of a 1x1 matrix ?? -// Pro: more natural for the user -// Cons: this could be a problem if in a meta unrolled algorithm a matrix-matrix -// product ends up to a row-vector times col-vector product... To tackle this use -// case, we could have a specialization for Block with: operator=(Scalar x); - -namespace internal { - -template -struct traits > - : traits::ReturnType,1,1> > -{}; - -} - -template -class GeneralProduct - : internal::no_assignment_operator, - public Matrix::ReturnType,1,1> -{ - typedef Matrix::ReturnType,1,1> Base; - public: - GeneralProduct(const Lhs& lhs, const Rhs& rhs) - { - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - Base::coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum(); - } - - /** Convertion to scalar */ - operator const typename Base::Scalar() const { - return Base::coeff(0,0); - } -}; - -/*********************************************************************** -* Implementation of Outer Vector Vector Product -***********************************************************************/ - -namespace internal { -template struct outer_product_selector; - -template -struct traits > - : traits, Lhs, Rhs> > -{}; - -} template -class GeneralProduct - : public ProductBase, Lhs, Rhs> +class Product : public ProductImpl::StorageKind, + typename internal::traits::StorageKind>::ret> { public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - - GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) + + typedef typename ProductImpl< + Lhs, Rhs, + typename internal::promote_storage_type::ret>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(Product) + + typedef typename Lhs::Nested LhsNested; + typedef typename Rhs::Nested RhsNested; + typedef typename internal::remove_all::type LhsNestedCleaned; + typedef typename internal::remove_all::type RhsNestedCleaned; + + Product(const Lhs& lhs, const Rhs& rhs) : m_lhs(lhs), m_rhs(rhs) { - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + eigen_assert(lhs.cols() == rhs.rows() + && "invalid matrix product" + && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); } - template void scaleAndAddTo(Dest& dest, Scalar alpha) const - { - internal::outer_product_selector<(int(Dest::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(*this, dest, alpha); - } -}; + inline Index rows() const { return m_lhs.rows(); } + inline Index cols() const { return m_rhs.cols(); } -namespace internal { + const LhsNestedCleaned& lhs() const { return m_lhs; } + const RhsNestedCleaned& rhs() const { return m_rhs; } -template<> struct outer_product_selector { - template - static EIGEN_DONT_INLINE void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) { - typedef typename Dest::Index Index; - // FIXME make sure lhs is sequentially stored - // FIXME not very good if rhs is real and lhs complex while alpha is real too - const Index cols = dest.cols(); - for (Index j=0; j struct outer_product_selector { - template - static EIGEN_DONT_INLINE void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) { - typedef typename Dest::Index Index; - // FIXME make sure rhs is sequentially stored - // FIXME not very good if lhs is real and rhs complex while alpha is real too - const Index rows = dest.rows(); - for (Index i=0; i call fast BLAS-like colmajor routine - * 2 - the matrix is row-major, BLAS compatible and N is large => call fast BLAS-like rowmajor routine - * 3 - all other cases are handled using a simple loop along the outer-storage direction. - * Therefore we need a lower level meta selector. - * Furthermore, if the matrix is the rhs, then the product has to be transposed. - */ -namespace internal { - -template -struct traits > - : traits, Lhs, Rhs> > -{}; - -template -struct gemv_selector; - -} // end namespace internal - template -class GeneralProduct - : public ProductBase, Lhs, Rhs> +class ProductImpl : public internal::dense_xpr_base >::type { + typedef Product Derived; public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - - typedef typename Lhs::Scalar LhsScalar; - typedef typename Rhs::Scalar RhsScalar; - - GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - { -// EIGEN_STATIC_ASSERT((internal::is_same::value), -// YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - } - - enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; - typedef typename internal::conditional::type MatrixType; - - template void scaleAndAddTo(Dest& dst, Scalar alpha) const - { - eigen_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols()); - internal::gemv_selector::HasUsableDirectAccess)>::run(*this, dst, alpha); - } -}; - -namespace internal { - -// The vector is on the left => transposition -template -struct gemv_selector -{ - template - static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) - { - Transpose destT(dest); - enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; - gemv_selector - ::run(GeneralProduct,Transpose, GemvProduct> - (prod.rhs().transpose(), prod.lhs().transpose()), destT, alpha); - } -}; - -template struct gemv_static_vector_if; - -template -struct gemv_static_vector_if -{ - EIGEN_STRONG_INLINE Scalar* data() { eigen_internal_assert(false && "should never be called"); return 0; } -}; - -template -struct gemv_static_vector_if -{ - EIGEN_STRONG_INLINE Scalar* data() { return 0; } -}; - -template -struct gemv_static_vector_if -{ - #if EIGEN_ALIGN_STATICALLY - internal::plain_array m_data; - EIGEN_STRONG_INLINE Scalar* data() { return m_data.array; } - #else - // Some architectures cannot align on the stack, - // => let's manually enforce alignment by allocating more data and return the address of the first aligned element. - enum { - ForceAlignment = internal::packet_traits::Vectorizable, - PacketSize = internal::packet_traits::size - }; - internal::plain_array m_data; - EIGEN_STRONG_INLINE Scalar* data() { - return ForceAlignment - ? reinterpret_cast((reinterpret_cast(m_data.array) & ~(size_t(15))) + 16) - : m_data.array; - } - #endif -}; - -template<> struct gemv_selector -{ - template - static inline void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) - { - typedef typename ProductType::Index Index; - typedef typename ProductType::LhsScalar LhsScalar; - typedef typename ProductType::RhsScalar RhsScalar; - typedef typename ProductType::Scalar ResScalar; - typedef typename ProductType::RealScalar RealScalar; - typedef typename ProductType::ActualLhsType ActualLhsType; - typedef typename ProductType::ActualRhsType ActualRhsType; - typedef typename ProductType::LhsBlasTraits LhsBlasTraits; - typedef typename ProductType::RhsBlasTraits RhsBlasTraits; - typedef Map, Aligned> MappedDest; - - const ActualLhsType actualLhs = LhsBlasTraits::extract(prod.lhs()); - const ActualRhsType actualRhs = RhsBlasTraits::extract(prod.rhs()); - - ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) - * RhsBlasTraits::extractScalarFactor(prod.rhs()); - - enum { - // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 - // on, the other hand it is good for the cache to pack the vector anyways... - EvalToDestAtCompileTime = Dest::InnerStrideAtCompileTime==1, - ComplexByReal = (NumTraits::IsComplex) && (!NumTraits::IsComplex), - MightCannotUseDest = (Dest::InnerStrideAtCompileTime!=1) || ComplexByReal - }; - - gemv_static_vector_if static_dest; - - // this is written like this (i.e., with a ?:) to workaround an ICE with ICC 12 - bool alphaIsCompatible = (!ComplexByReal) ? true : (imag(actualAlpha)==RealScalar(0)); - bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible; - - RhsScalar compatibleAlpha = get_factor::run(actualAlpha); - - ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(), - evalToDest ? dest.data() : static_dest.data()); - - if(!evalToDest) - { - #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - int size = dest.size(); - EIGEN_DENSE_STORAGE_CTOR_PLUGIN - #endif - if(!alphaIsCompatible) - { - MappedDest(actualDestPtr, dest.size()).setZero(); - compatibleAlpha = RhsScalar(1); - } - else - MappedDest(actualDestPtr, dest.size()) = dest; - } - general_matrix_vector_product - ::run( - actualLhs.rows(), actualLhs.cols(), - &actualLhs.coeffRef(0,0), actualLhs.outerStride(), - actualRhs.data(), actualRhs.innerStride(), - actualDestPtr, 1, - compatibleAlpha); - - if (!evalToDest) - { - if(!alphaIsCompatible) - dest += actualAlpha * MappedDest(actualDestPtr, dest.size()); - else - dest = MappedDest(actualDestPtr, dest.size()); - } - } -}; - -template<> struct gemv_selector -{ - template - static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) - { - typedef typename ProductType::LhsScalar LhsScalar; - typedef typename ProductType::RhsScalar RhsScalar; - typedef typename ProductType::Scalar ResScalar; - typedef typename ProductType::Index Index; - typedef typename ProductType::ActualLhsType ActualLhsType; - typedef typename ProductType::ActualRhsType ActualRhsType; - typedef typename ProductType::_ActualRhsType _ActualRhsType; - typedef typename ProductType::LhsBlasTraits LhsBlasTraits; - typedef typename ProductType::RhsBlasTraits RhsBlasTraits; - - typename add_const::type actualLhs = LhsBlasTraits::extract(prod.lhs()); - typename add_const::type actualRhs = RhsBlasTraits::extract(prod.rhs()); - - ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) - * RhsBlasTraits::extractScalarFactor(prod.rhs()); - - enum { - // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 - // on, the other hand it is good for the cache to pack the vector anyways... - DirectlyUseRhs = _ActualRhsType::InnerStrideAtCompileTime==1 - }; - - gemv_static_vector_if static_rhs; - - ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,actualRhs.size(), - DirectlyUseRhs ? const_cast(actualRhs.data()) : static_rhs.data()); - - if(!DirectlyUseRhs) - { - #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - int size = actualRhs.size(); - EIGEN_DENSE_STORAGE_CTOR_PLUGIN - #endif - Map(actualRhsPtr, actualRhs.size()) = actualRhs; - } - - general_matrix_vector_product - ::run( - actualLhs.rows(), actualLhs.cols(), - &actualLhs.coeffRef(0,0), actualLhs.outerStride(), - actualRhsPtr, 1, - &dest.coeffRef(0,0), dest.innerStride(), - actualAlpha); - } -}; - -template<> struct gemv_selector -{ - template - static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) - { - typedef typename Dest::Index Index; - // TODO makes sure dest is sequentially stored in memory, otherwise use a temp - const Index size = prod.rhs().rows(); - for(Index k=0; k struct gemv_selector -{ - template - static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) - { - typedef typename Dest::Index Index; - // TODO makes sure rhs is sequentially stored in memory, otherwise use a temp - const Index rows = prod.rows(); - for(Index i=0; i >::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Derived) }; -} // end namespace internal - -/*************************************************************************** -* Implementation of matrix base methods -***************************************************************************/ - -/** \returns the matrix product of \c *this and \a other. - * - * \note If instead of the matrix product you want the coefficient-wise product, see Cwise::operator*(). - * - * \sa lazyProduct(), operator*=(const MatrixBase&), Cwise::operator*() - */ -template -template -inline const typename ProductReturnType::Type -MatrixBase::operator*(const MatrixBase &other) const -{ - // A note regarding the function declaration: In MSVC, this function will sometimes - // not be inlined since DenseStorage is an unwindable object for dynamic - // matrices and product types are holding a member to store the result. - // Thus it does not help tagging this function with EIGEN_STRONG_INLINE. - enum { - ProductIsValid = Derived::ColsAtCompileTime==Dynamic - || OtherDerived::RowsAtCompileTime==Dynamic - || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime), - AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime, - SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived) - }; - // note to the lost user: - // * for a dot product use: v1.dot(v2) - // * for a coeff-wise product use: v1.cwiseProduct(v2) - EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), - INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) - EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), - INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) - EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) -#ifdef EIGEN_DEBUG_PRODUCT - internal::product_type::debug(); -#endif - return typename ProductReturnType::Type(derived(), other.derived()); -} - -/** \returns an expression of the matrix product of \c *this and \a other without implicit evaluation. - * - * The returned product will behave like any other expressions: the coefficients of the product will be - * computed once at a time as requested. This might be useful in some extremely rare cases when only - * a small and no coherent fraction of the result's coefficients have to be computed. - * - * \warning This version of the matrix product can be much much slower. So use it only if you know - * what you are doing and that you measured a true speed improvement. - * - * \sa operator*(const MatrixBase&) - */ -template -template -const typename LazyProductReturnType::Type -MatrixBase::lazyProduct(const MatrixBase &other) const -{ - enum { - ProductIsValid = Derived::ColsAtCompileTime==Dynamic - || OtherDerived::RowsAtCompileTime==Dynamic - || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime), - AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime, - SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived) - }; - // note to the lost user: - // * for a dot product use: v1.dot(v2) - // * for a coeff-wise product use: v1.cwiseProduct(v2) - EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), - INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) - EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), - INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) - EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) - - return typename LazyProductReturnType::Type(derived(), other.derived()); -} - #endif // EIGEN_PRODUCT_H diff --git a/extern/Eigen3/Eigen/src/Core/ProductBase.h b/extern/Eigen3/Eigen/src/Core/ProductBase.h index 91975880fdc..ec12e5c9f6b 100644 --- a/extern/Eigen3/Eigen/src/Core/ProductBase.h +++ b/extern/Eigen3/Eigen/src/Core/ProductBase.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_PRODUCTBASE_H #define EIGEN_PRODUCTBASE_H +namespace Eigen { + /** \class ProductBase * \ingroup Core_Module * @@ -115,10 +102,10 @@ class ProductBase : public MatrixBase inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst,Scalar(1)); } template - inline void addTo(Dest& dst) const { scaleAndAddTo(dst,1); } + inline void addTo(Dest& dst) const { scaleAndAddTo(dst,Scalar(1)); } template - inline void subTo(Dest& dst) const { scaleAndAddTo(dst,-1); } + inline void subTo(Dest& dst) const { scaleAndAddTo(dst,Scalar(-1)); } template inline void scaleAndAddTo(Dest& dst,Scalar alpha) const { derived().scaleAndAddTo(dst,alpha); } @@ -181,8 +168,8 @@ class ProductBase : public MatrixBase protected: - const LhsNested m_lhs; - const RhsNested m_rhs; + LhsNested m_lhs; + RhsNested m_rhs; mutable PlainObject m_result; }; @@ -286,5 +273,6 @@ Derived& MatrixBase::lazyAssign(const ProductBase // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_RANDOM_H #define EIGEN_RANDOM_H +namespace Eigen { + namespace internal { template struct scalar_random_op { @@ -160,4 +147,6 @@ PlainObjectBase::setRandom(Index rows, Index cols) return setRandom(); } +} // end namespace Eigen + #endif // EIGEN_RANDOM_H diff --git a/extern/Eigen3/Eigen/src/Core/Redux.h b/extern/Eigen3/Eigen/src/Core/Redux.h index f9f5a95d546..b7ce7c658a2 100644 --- a/extern/Eigen3/Eigen/src/Core/Redux.h +++ b/extern/Eigen3/Eigen/src/Core/Redux.h @@ -4,28 +4,15 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_REDUX_H #define EIGEN_REDUX_H +namespace Eigen { + namespace internal { // TODO @@ -95,7 +82,7 @@ struct redux_novec_unroller typedef typename Derived::Scalar Scalar; - EIGEN_STRONG_INLINE static Scalar run(const Derived &mat, const Func& func) + static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) { return func(redux_novec_unroller::run(mat,func), redux_novec_unroller::run(mat,func)); @@ -112,7 +99,7 @@ struct redux_novec_unroller typedef typename Derived::Scalar Scalar; - EIGEN_STRONG_INLINE static Scalar run(const Derived &mat, const Func&) + static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func&) { return mat.coeffByOuterInner(outer, inner); } @@ -125,7 +112,7 @@ template struct redux_novec_unroller { typedef typename Derived::Scalar Scalar; - EIGEN_STRONG_INLINE static Scalar run(const Derived&, const Func&) { return Scalar(); } + static EIGEN_STRONG_INLINE Scalar run(const Derived&, const Func&) { return Scalar(); } }; /*** vectorization ***/ @@ -141,7 +128,7 @@ struct redux_vec_unroller typedef typename Derived::Scalar Scalar; typedef typename packet_traits::type PacketScalar; - EIGEN_STRONG_INLINE static PacketScalar run(const Derived &mat, const Func& func) + static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func& func) { return func.packetOp( redux_vec_unroller::run(mat,func), @@ -162,7 +149,7 @@ struct redux_vec_unroller typedef typename Derived::Scalar Scalar; typedef typename packet_traits::type PacketScalar; - EIGEN_STRONG_INLINE static PacketScalar run(const Derived &mat, const Func&) + static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func&) { return mat.template packetByOuterInner(outer, inner); } @@ -214,20 +201,33 @@ struct redux_impl const Index size = mat.size(); eigen_assert(size && "you are using an empty matrix"); const Index packetSize = packet_traits::size; - const Index alignedStart = first_aligned(mat); + const Index alignedStart = internal::first_aligned(mat); enum { alignment = bool(Derived::Flags & DirectAccessBit) || bool(Derived::Flags & AlignedBit) ? Aligned : Unaligned }; - const Index alignedSize = ((size-alignedStart)/packetSize)*packetSize; - const Index alignedEnd = alignedStart + alignedSize; + const Index alignedSize2 = ((size-alignedStart)/(2*packetSize))*(2*packetSize); + const Index alignedSize = ((size-alignedStart)/(packetSize))*(packetSize); + const Index alignedEnd2 = alignedStart + alignedSize2; + const Index alignedEnd = alignedStart + alignedSize; Scalar res; if(alignedSize) { - PacketScalar packet_res = mat.template packet(alignedStart); - for(Index index = alignedStart + packetSize; index < alignedEnd; index += packetSize) - packet_res = func.packetOp(packet_res, mat.template packet(index)); - res = func.predux(packet_res); + PacketScalar packet_res0 = mat.template packet(alignedStart); + if(alignedSize>packetSize) // we have at least two packets to partly unroll the loop + { + PacketScalar packet_res1 = mat.template packet(alignedStart+packetSize); + for(Index index = alignedStart + 2*packetSize; index < alignedEnd2; index += 2*packetSize) + { + packet_res0 = func.packetOp(packet_res0, mat.template packet(index)); + packet_res1 = func.packetOp(packet_res1, mat.template packet(index+packetSize)); + } + + packet_res0 = func.packetOp(packet_res0,packet_res1); + if(alignedEnd>alignedEnd2) + packet_res0 = func.packetOp(packet_res0, mat.template packet(alignedEnd2)); + } + res = func.predux(packet_res0); for(Index index = 0; index < alignedStart; ++index) res = func(res,mat.coeff(index)); @@ -296,7 +296,7 @@ struct redux_impl Size = Derived::SizeAtCompileTime, VectorizedSize = (Size / PacketSize) * PacketSize }; - EIGEN_STRONG_INLINE static Scalar run(const Derived& mat, const Func& func) + static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); Scalar res = func.predux(redux_vec_unroller::run(mat,func)); @@ -401,4 +401,6 @@ MatrixBase::trace() const return derived().diagonal().sum(); } +} // end namespace Eigen + #endif // EIGEN_REDUX_H diff --git a/extern/Eigen3/Eigen/src/Core/Replicate.h b/extern/Eigen3/Eigen/src/Core/Replicate.h index 4c171f8d580..b61fdc29e2f 100644 --- a/extern/Eigen3/Eigen/src/Core/Replicate.h +++ b/extern/Eigen3/Eigen/src/Core/Replicate.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_REPLICATE_H #define EIGEN_REPLICATE_H +namespace Eigen { + /** * \class Replicate * \ingroup Core_Module @@ -92,7 +79,7 @@ template class Replicate } template - inline Replicate(const OriginalMatrixType& matrix, int rowFactor, int colFactor) + inline Replicate(const OriginalMatrixType& matrix, Index rowFactor, Index colFactor) : m_matrix(matrix), m_rowFactor(rowFactor), m_colFactor(colFactor) { EIGEN_STATIC_ASSERT((internal::is_same::type,OriginalMatrixType>::value), @@ -127,9 +114,13 @@ template class Replicate return m_matrix.template packet(actual_row, actual_col); } + const _MatrixTypeNested& nestedExpression() const + { + return m_matrix; + } protected: - const MatrixTypeNested m_matrix; + MatrixTypeNested m_matrix; const internal::variable_if_dynamic m_rowFactor; const internal::variable_if_dynamic m_colFactor; }; @@ -181,4 +172,6 @@ VectorwiseOp::replicate(Index factor) const (_expression(),Direction==Vertical?factor:1,Direction==Horizontal?factor:1); } +} // end namespace Eigen + #endif // EIGEN_REPLICATE_H diff --git a/extern/Eigen3/Eigen/src/Core/ReturnByValue.h b/extern/Eigen3/Eigen/src/Core/ReturnByValue.h index 24c5a4e215d..613912ffa8c 100644 --- a/extern/Eigen3/Eigen/src/Core/ReturnByValue.h +++ b/extern/Eigen3/Eigen/src/Core/ReturnByValue.h @@ -4,28 +4,15 @@ // Copyright (C) 2009-2010 Gael Guennebaud // Copyright (C) 2009-2010 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_RETURNBYVALUE_H #define EIGEN_RETURNBYVALUE_H +namespace Eigen { + /** \class ReturnByValue * \ingroup Core_Module * @@ -96,4 +83,6 @@ Derived& DenseBase::operator=(const ReturnByValue& other) return derived(); } +} // end namespace Eigen + #endif // EIGEN_RETURNBYVALUE_H diff --git a/extern/Eigen3/Eigen/src/Core/Reverse.h b/extern/Eigen3/Eigen/src/Core/Reverse.h index 600744ae758..e30ae3d281b 100644 --- a/extern/Eigen3/Eigen/src/Core/Reverse.h +++ b/extern/Eigen3/Eigen/src/Core/Reverse.h @@ -5,28 +5,15 @@ // Copyright (C) 2009 Ricard Marxer // Copyright (C) 2009-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_REVERSE_H #define EIGEN_REVERSE_H +namespace Eigen { + /** \class Reverse * \ingroup Core_Module * @@ -183,8 +170,14 @@ template class Reverse m_matrix.const_cast_derived().template writePacket(m_matrix.size() - index - PacketSize, internal::preverse(x)); } + const typename internal::remove_all::type& + nestedExpression() const + { + return m_matrix; + } + protected: - const typename MatrixType::Nested m_matrix; + typename MatrixType::Nested m_matrix; }; /** \returns an expression of the reverse of *this. @@ -226,5 +219,6 @@ inline void DenseBase::reverseInPlace() derived() = derived().reverse().eval(); } +} // end namespace Eigen #endif // EIGEN_REVERSE_H diff --git a/extern/Eigen3/Eigen/src/Core/Select.h b/extern/Eigen3/Eigen/src/Core/Select.h index d0cd66a261a..2bf6e91d0aa 100644 --- a/extern/Eigen3/Eigen/src/Core/Select.h +++ b/extern/Eigen3/Eigen/src/Core/Select.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SELECT_H #define EIGEN_SELECT_H +namespace Eigen { + /** \class Select * \ingroup Core_Module * @@ -101,10 +88,25 @@ class Select : internal::no_assignment_operator, return m_else.coeff(i); } + const ConditionMatrixType& conditionMatrix() const + { + return m_condition; + } + + const ThenMatrixType& thenMatrix() const + { + return m_then; + } + + const ElseMatrixType& elseMatrix() const + { + return m_else; + } + protected: - const typename ConditionMatrixType::Nested m_condition; - const typename ThenMatrixType::Nested m_then; - const typename ElseMatrixType::Nested m_else; + typename ConditionMatrixType::Nested m_condition; + typename ThenMatrixType::Nested m_then; + typename ElseMatrixType::Nested m_else; }; @@ -155,4 +157,6 @@ DenseBase::select(typename ElseDerived::Scalar thenScalar, derived(), ElseDerived::Constant(rows(),cols(),thenScalar), elseMatrix.derived()); } +} // end namespace Eigen + #endif // EIGEN_SELECT_H diff --git a/extern/Eigen3/Eigen/src/Core/SelfAdjointView.h b/extern/Eigen3/Eigen/src/Core/SelfAdjointView.h index 4bb68755eee..82cc4da736a 100644 --- a/extern/Eigen3/Eigen/src/Core/SelfAdjointView.h +++ b/extern/Eigen3/Eigen/src/Core/SelfAdjointView.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SELFADJOINTMATRIX_H #define EIGEN_SELFADJOINTMATRIX_H +namespace Eigen { + /** \class SelfAdjointView * \ingroup Core_Module * @@ -82,7 +69,7 @@ template class SelfAdjointView }; typedef typename MatrixType::PlainObject PlainObject; - inline SelfAdjointView(const MatrixType& matrix) : m_matrix(matrix) + inline SelfAdjointView(MatrixType& matrix) : m_matrix(matrix) {} inline Index rows() const { return m_matrix.rows(); } @@ -199,7 +186,7 @@ template class SelfAdjointView #endif protected: - const MatrixTypeNested m_matrix; + MatrixTypeNested m_matrix; }; @@ -222,7 +209,7 @@ struct triangular_assignment_selector::run(dst, src); @@ -236,7 +223,7 @@ struct triangular_assignment_selector struct triangular_assignment_selector { - inline static void run(Derived1 &, const Derived2 &) {} + static inline void run(Derived1 &, const Derived2 &) {} }; template @@ -247,7 +234,7 @@ struct triangular_assignment_selector::run(dst, src); @@ -261,14 +248,14 @@ struct triangular_assignment_selector struct triangular_assignment_selector { - inline static void run(Derived1 &, const Derived2 &) {} + static inline void run(Derived1 &, const Derived2 &) {} }; template struct triangular_assignment_selector { typedef typename Derived1::Index Index; - inline static void run(Derived1 &dst, const Derived2 &src) + static inline void run(Derived1 &dst, const Derived2 &src) { for(Index j = 0; j < dst.cols(); ++j) { @@ -285,7 +272,7 @@ struct triangular_assignment_selector struct triangular_assignment_selector { - inline static void run(Derived1 &dst, const Derived2 &src) + static inline void run(Derived1 &dst, const Derived2 &src) { typedef typename Derived1::Index Index; for(Index i = 0; i < dst.rows(); ++i) @@ -322,4 +309,6 @@ MatrixBase::selfadjointView() return derived(); } +} // end namespace Eigen + #endif // EIGEN_SELFADJOINTMATRIX_H diff --git a/extern/Eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h b/extern/Eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h index 4e9ca88745d..0caf2bab1d8 100644 --- a/extern/Eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h +++ b/extern/Eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SELFCWISEBINARYOP_H #define EIGEN_SELFCWISEBINARYOP_H +namespace Eigen { + /** \class SelfCwiseBinaryOp * \ingroup Core_Module * @@ -163,6 +150,16 @@ template class SelfCwiseBinaryOp return Base::operator=(rhs); } + Lhs& expression() const + { + return m_matrix; + } + + const BinaryOp& functor() const + { + return m_functor; + } + protected: Lhs& m_matrix; const BinaryOp& m_functor; @@ -192,4 +189,6 @@ inline Derived& DenseBase::operator/=(const Scalar& other) return derived(); } +} // end namespace Eigen + #endif // EIGEN_SELFCWISEBINARYOP_H diff --git a/extern/Eigen3/Eigen/src/Core/SolveTriangular.h b/extern/Eigen3/Eigen/src/Core/SolveTriangular.h index a23014a343f..ef17f288e29 100644 --- a/extern/Eigen3/Eigen/src/Core/SolveTriangular.h +++ b/extern/Eigen3/Eigen/src/Core/SolveTriangular.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008-2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SOLVETRIANGULAR_H #define EIGEN_SOLVETRIANGULAR_H +namespace Eigen { + namespace internal { // Forward declarations: @@ -98,12 +85,22 @@ struct triangular_solver_selector typedef typename Rhs::Index Index; typedef blas_traits LhsProductTraits; typedef typename LhsProductTraits::DirectLinearAccessType ActualLhsType; + static void run(const Lhs& lhs, Rhs& rhs) { - const ActualLhsType actualLhs = LhsProductTraits::extract(lhs); + typename internal::add_const_on_value_type::type actualLhs = LhsProductTraits::extract(lhs); + + const Index size = lhs.rows(); + const Index othersize = Side==OnTheLeft? rhs.cols() : rhs.rows(); + + typedef internal::gemm_blocking_space<(Rhs::Flags&RowMajorBit) ? RowMajor : ColMajor,Scalar,Scalar, + Rhs::MaxRowsAtCompileTime, Rhs::MaxColsAtCompileTime, Lhs::MaxRowsAtCompileTime,4> BlockingType; + + BlockingType blocking(rhs.rows(), rhs.cols(), size); + triangular_solve_matrix - ::run(lhs.rows(), Side==OnTheLeft? rhs.cols() : rhs.rows(), &actualLhs.coeffRef(0,0), actualLhs.outerStride(), &rhs.coeffRef(0,0), rhs.outerStride()); + ::run(size, othersize, &actualLhs.coeffRef(0,0), actualLhs.outerStride(), &rhs.coeffRef(0,0), rhs.outerStride(), blocking); } }; @@ -177,10 +174,8 @@ template void TriangularView::solveInPlace(const MatrixBase& _other) const { OtherDerived& other = _other.const_cast_derived(); - eigen_assert(cols() == rows()); - eigen_assert( (Side==OnTheLeft && cols() == other.rows()) || (Side==OnTheRight && cols() == other.cols()) ); - eigen_assert(!(Mode & ZeroDiag)); - eigen_assert((Mode & (Upper|Lower)) != 0); + eigen_assert( cols() == rows() && ((Side==OnTheLeft && cols() == other.rows()) || (Side==OnTheRight && cols() == other.cols())) ); + eigen_assert((!(Mode & ZeroDiag)) && bool(Mode & (Upper|Lower))); enum { copy = internal::traits::Flags & RowMajorBit && OtherDerived::IsVectorAtCompileTime }; typedef typename internal::conditional struct triangular_solv protected: const TriangularType& m_triangularMatrix; - const typename Rhs::Nested m_rhs; + typename Rhs::Nested m_rhs; }; } // namespace internal +} // end namespace Eigen + #endif // EIGEN_SOLVETRIANGULAR_H diff --git a/extern/Eigen3/Eigen/src/Core/StableNorm.h b/extern/Eigen3/Eigen/src/Core/StableNorm.h index f667272e4a4..d8bf7db70e4 100644 --- a/extern/Eigen3/Eigen/src/Core/StableNorm.h +++ b/extern/Eigen3/Eigen/src/Core/StableNorm.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_STABLENORM_H #define EIGEN_STABLENORM_H +namespace Eigen { + namespace internal { template inline void stable_norm_kernel(const ExpressionType& bl, Scalar& ssq, Scalar& scale, Scalar& invScale) @@ -58,9 +45,9 @@ MatrixBase::stableNorm() const { using std::min; const Index blockSize = 4096; - RealScalar scale = 0; - RealScalar invScale = 1; - RealScalar ssq = 0; // sum of square + RealScalar scale(0); + RealScalar invScale(1); + RealScalar ssq(0); // sum of square enum { Alignment = (int(Flags)&DirectAccessBit) || (int(Flags)&AlignedBit) ? 1 : 0 }; @@ -187,4 +174,6 @@ MatrixBase::hypotNorm() const return this->cwiseAbs().redux(internal::scalar_hypot_op()); } +} // end namespace Eigen + #endif // EIGEN_STABLENORM_H diff --git a/extern/Eigen3/Eigen/src/Core/Stride.h b/extern/Eigen3/Eigen/src/Core/Stride.h index 0430f111627..1e3f5fe9fff 100644 --- a/extern/Eigen3/Eigen/src/Core/Stride.h +++ b/extern/Eigen3/Eigen/src/Core/Stride.h @@ -3,28 +3,15 @@ // // Copyright (C) 2010 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_STRIDE_H #define EIGEN_STRIDE_H +namespace Eigen { + /** \class Stride * \ingroup Core_Module * @@ -116,4 +103,6 @@ class OuterStride : public Stride OuterStride(Index v) : Base(v,0) {} }; +} // end namespace Eigen + #endif // EIGEN_STRIDE_H diff --git a/extern/Eigen3/Eigen/src/Core/Swap.h b/extern/Eigen3/Eigen/src/Core/Swap.h index 5fb03286675..fd73cf3ad7e 100644 --- a/extern/Eigen3/Eigen/src/Core/Swap.h +++ b/extern/Eigen3/Eigen/src/Core/Swap.h @@ -3,28 +3,15 @@ // // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SWAP_H #define EIGEN_SWAP_H +namespace Eigen { + /** \class SwapWrapper * \ingroup Core_Module * @@ -52,6 +39,15 @@ template class SwapWrapper inline Index cols() const { return m_expression.cols(); } inline Index outerStride() const { return m_expression.outerStride(); } inline Index innerStride() const { return m_expression.innerStride(); } + + typedef typename internal::conditional< + internal::is_lvalue::value, + Scalar, + const Scalar + >::type ScalarWithConstIfNotLvalue; + + inline ScalarWithConstIfNotLvalue* data() { return m_expression.data(); } + inline const Scalar* data() const { return m_expression.data(); } inline Scalar& coeffRef(Index row, Index col) { @@ -119,8 +115,12 @@ template class SwapWrapper _other.template writePacket(index, tmp); } + ExpressionType& expression() const { return m_expression; } + protected: ExpressionType& m_expression; }; +} // end namespace Eigen + #endif // EIGEN_SWAP_H diff --git a/extern/Eigen3/Eigen/src/Core/Transpose.h b/extern/Eigen3/Eigen/src/Core/Transpose.h index 3f7c7df6ee1..045a1cce671 100644 --- a/extern/Eigen3/Eigen/src/Core/Transpose.h +++ b/extern/Eigen3/Eigen/src/Core/Transpose.h @@ -4,28 +4,15 @@ // Copyright (C) 2006-2008 Benoit Jacob // Copyright (C) 2009-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_TRANSPOSE_H #define EIGEN_TRANSPOSE_H +namespace Eigen { + /** \class Transpose * \ingroup Core_Module * @@ -91,7 +78,7 @@ template class Transpose nestedExpression() { return m_matrix.const_cast_derived(); } protected: - const typename MatrixType::Nested m_matrix; + typename MatrixType::Nested m_matrix; }; namespace internal { @@ -152,12 +139,12 @@ template class TransposeImpl return derived().nestedExpression().coeffRef(index); } - inline const CoeffReturnType coeff(Index row, Index col) const + inline CoeffReturnType coeff(Index row, Index col) const { return derived().nestedExpression().coeff(col, row); } - inline const CoeffReturnType coeff(Index index) const + inline CoeffReturnType coeff(Index index) const { return derived().nestedExpression().coeff(index); } @@ -422,4 +409,6 @@ void DenseBase::checkTransposeAliasing(const OtherDerived& other) const } #endif +} // end namespace Eigen + #endif // EIGEN_TRANSPOSE_H diff --git a/extern/Eigen3/Eigen/src/Core/Transpositions.h b/extern/Eigen3/Eigen/src/Core/Transpositions.h index 88fdfb2226f..2cd268a5fa0 100644 --- a/extern/Eigen3/Eigen/src/Core/Transpositions.h +++ b/extern/Eigen3/Eigen/src/Core/Transpositions.h @@ -3,28 +3,15 @@ // // Copyright (C) 2010-2011 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_TRANSPOSITIONS_H #define EIGEN_TRANSPOSITIONS_H +namespace Eigen { + /** \class Transpositions * \ingroup Core_Module * @@ -404,7 +391,7 @@ struct transposition_matrix_product_retval protected: const TranspositionType& m_transpositions; - const typename MatrixType::Nested m_matrix; + typename MatrixType::Nested m_matrix; }; } // end namespace internal @@ -444,4 +431,6 @@ class Transpose > const TranspositionType& m_transpositions; }; +} // end namespace Eigen + #endif // EIGEN_TRANSPOSITIONS_H diff --git a/extern/Eigen3/Eigen/src/Core/TriangularMatrix.h b/extern/Eigen3/Eigen/src/Core/TriangularMatrix.h index 033e81036f3..de9540063c2 100644 --- a/extern/Eigen3/Eigen/src/Core/TriangularMatrix.h +++ b/extern/Eigen3/Eigen/src/Core/TriangularMatrix.h @@ -4,28 +4,15 @@ // Copyright (C) 2008 Benoit Jacob // Copyright (C) 2008-2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_TRIANGULARMATRIX_H #define EIGEN_TRIANGULARMATRIX_H +namespace Eigen { + namespace internal { template struct triangular_solve_retval; @@ -273,11 +260,8 @@ template class TriangularView inline const TriangularView conjugate() const { return m_matrix.conjugate(); } - /** \sa MatrixBase::adjoint() */ - inline TriangularView adjoint() - { return m_matrix.adjoint(); } /** \sa MatrixBase::adjoint() const */ - inline const TriangularView adjoint() const + inline const TriangularView adjoint() const { return m_matrix.adjoint(); } /** \sa MatrixBase::transpose() */ @@ -288,11 +272,13 @@ template class TriangularView } /** \sa MatrixBase::transpose() const */ inline const TriangularView,TransposeMode> transpose() const - { return m_matrix.transpose(); } + { + return m_matrix.transpose(); + } /** Efficient triangular matrix times vector/matrix product */ template - TriangularProduct + TriangularProduct operator*(const MatrixBase& rhs) const { return TriangularProduct @@ -375,7 +361,8 @@ template class TriangularView template void swap(MatrixBase const & other) { - TriangularView,Mode>(const_cast(m_matrix)).lazyAssign(other.derived()); + SwapWrapper swaper(const_cast(m_matrix)); + TriangularView,Mode>(swaper).lazyAssign(other.derived()); } Scalar determinant() const @@ -433,7 +420,7 @@ template class TriangularView template EIGEN_STRONG_INLINE TriangularView& assignProduct(const ProductBase& prod, const Scalar& alpha); - const MatrixTypeNested m_matrix; + MatrixTypeNested m_matrix; }; /*************************************************************************** @@ -452,7 +439,7 @@ struct triangular_assignment_selector typedef typename Derived1::Scalar Scalar; - inline static void run(Derived1 &dst, const Derived2 &src) + static inline void run(Derived1 &dst, const Derived2 &src) { triangular_assignment_selector::run(dst, src); @@ -480,7 +467,7 @@ struct triangular_assignment_selector template struct triangular_assignment_selector { - inline static void run(Derived1 &, const Derived2 &) {} + static inline void run(Derived1 &, const Derived2 &) {} }; template @@ -488,7 +475,7 @@ struct triangular_assignment_selector struct triangular_assignment_selector { typedef typename Derived1::Index Index; - inline static void run(Derived1 &dst, const Derived2 &src) + static inline void run(Derived1 &dst, const Derived2 &src) { for(Index j = 0; j < dst.cols(); ++j) { @@ -524,7 +511,7 @@ template struct triangular_assignment_selector { typedef typename Derived1::Index Index; - inline static void run(Derived1 &dst, const Derived2 &src) + static inline void run(Derived1 &dst, const Derived2 &src) { for(Index j = 0; j < dst.cols(); ++j) { @@ -542,7 +529,7 @@ template struct triangular_assignment_selector { typedef typename Derived1::Index Index; - inline static void run(Derived1 &dst, const Derived2 &src) + static inline void run(Derived1 &dst, const Derived2 &src) { for(Index j = 0; j < dst.cols(); ++j) { @@ -560,7 +547,7 @@ template struct triangular_assignment_selector { typedef typename Derived1::Index Index; - inline static void run(Derived1 &dst, const Derived2 &src) + static inline void run(Derived1 &dst, const Derived2 &src) { for(Index j = 0; j < dst.cols(); ++j) { @@ -580,7 +567,7 @@ template struct triangular_assignment_selector { typedef typename Derived1::Index Index; - inline static void run(Derived1 &dst, const Derived2 &src) + static inline void run(Derived1 &dst, const Derived2 &src) { for(Index j = 0; j < dst.cols(); ++j) { @@ -835,4 +822,6 @@ bool MatrixBase::isLowerTriangular(RealScalar prec) const return true; } +} // end namespace Eigen + #endif // EIGEN_TRIANGULARMATRIX_H diff --git a/extern/Eigen3/Eigen/src/Core/VectorBlock.h b/extern/Eigen3/Eigen/src/Core/VectorBlock.h index 858e4c7865a..6f4effca055 100644 --- a/extern/Eigen3/Eigen/src/Core/VectorBlock.h +++ b/extern/Eigen3/Eigen/src/Core/VectorBlock.h @@ -4,28 +4,15 @@ // Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_VECTORBLOCK_H #define EIGEN_VECTORBLOCK_H +namespace Eigen { + /** \class VectorBlock * \ingroup Core_Module * @@ -292,5 +279,6 @@ DenseBase::tail() const return typename ConstFixedSegmentReturnType::Type(derived(), size() - Size); } +} // end namespace Eigen #endif // EIGEN_VECTORBLOCK_H diff --git a/extern/Eigen3/Eigen/src/Core/VectorwiseOp.h b/extern/Eigen3/Eigen/src/Core/VectorwiseOp.h index 20f6881575b..862c0f33608 100644 --- a/extern/Eigen3/Eigen/src/Core/VectorwiseOp.h +++ b/extern/Eigen3/Eigen/src/Core/VectorwiseOp.h @@ -4,28 +4,15 @@ // Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_PARTIAL_REDUX_H #define EIGEN_PARTIAL_REDUX_H +namespace Eigen { + /** \class PartialReduxExpr * \ingroup Core_Module * @@ -110,7 +97,7 @@ class PartialReduxExpr : internal::no_assignment_operator, } protected: - const MatrixTypeNested m_matrix; + MatrixTypeNested m_matrix; const MemberOp m_functor; }; @@ -237,7 +224,10 @@ template class VectorwiseOp typename ExtendedType::Type extendedTo(const DenseBase& other) const { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived); + EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(Direction==Vertical, OtherDerived::MaxColsAtCompileTime==1), + YOU_PASSED_A_ROW_VECTOR_BUT_A_COLUMN_VECTOR_WAS_EXPECTED) + EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(Direction==Horizontal, OtherDerived::MaxRowsAtCompileTime==1), + YOU_PASSED_A_COLUMN_VECTOR_BUT_A_ROW_VECTOR_WAS_EXPECTED) return typename ExtendedType::Type (other.derived(), Direction==Vertical ? 1 : m_matrix.rows(), @@ -418,10 +408,9 @@ template class VectorwiseOp ExpressionType& operator=(const DenseBase& other) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) + EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived) //eigen_assert((m_matrix.isNull()) == (other.isNull())); FIXME - for(Index j=0; j(m_matrix); + return const_cast(m_matrix = extendedTo(other.derived())); } /** Adds the vector \a other to each subvector of \c *this */ @@ -429,9 +418,8 @@ template class VectorwiseOp ExpressionType& operator+=(const DenseBase& other) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) - for(Index j=0; j(m_matrix); + EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived) + return const_cast(m_matrix += extendedTo(other.derived())); } /** Substracts the vector \a other to each subvector of \c *this */ @@ -439,8 +427,29 @@ template class VectorwiseOp ExpressionType& operator-=(const DenseBase& other) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) - for(Index j=0; j(m_matrix -= extendedTo(other.derived())); + } + + /** Multiples each subvector of \c *this by the vector \a other */ + template + ExpressionType& operator*=(const DenseBase& other) + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) + EIGEN_STATIC_ASSERT_ARRAYXPR(ExpressionType) + EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived) + m_matrix *= extendedTo(other.derived()); + return const_cast(m_matrix); + } + + /** Divides each subvector of \c *this by the vector \a other */ + template + ExpressionType& operator/=(const DenseBase& other) + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) + EIGEN_STATIC_ASSERT_ARRAYXPR(ExpressionType) + EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived) + m_matrix /= extendedTo(other.derived()); return const_cast(m_matrix); } @@ -451,7 +460,8 @@ template class VectorwiseOp const typename ExtendedType::Type> operator+(const DenseBase& other) const { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived); + EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) + EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived) return m_matrix + extendedTo(other.derived()); } @@ -462,10 +472,39 @@ template class VectorwiseOp const typename ExtendedType::Type> operator-(const DenseBase& other) const { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived); + EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) + EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived) return m_matrix - extendedTo(other.derived()); } + /** Returns the expression where each subvector is the product of the vector \a other + * by the corresponding subvector of \c *this */ + template EIGEN_STRONG_INLINE + CwiseBinaryOp, + const ExpressionTypeNestedCleaned, + const typename ExtendedType::Type> + operator*(const DenseBase& other) const + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) + EIGEN_STATIC_ASSERT_ARRAYXPR(ExpressionType) + EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived) + return m_matrix * extendedTo(other.derived()); + } + + /** Returns the expression where each subvector is the quotient of the corresponding + * subvector of \c *this by the vector \a other */ + template + CwiseBinaryOp, + const ExpressionTypeNestedCleaned, + const typename ExtendedType::Type> + operator/(const DenseBase& other) const + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) + EIGEN_STATIC_ASSERT_ARRAYXPR(ExpressionType) + EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived) + return m_matrix / extendedTo(other.derived()); + } + /////////// Geometry module /////////// #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS @@ -509,7 +548,7 @@ template class VectorwiseOp * Example: \include MatrixBase_colwise.cpp * Output: \verbinclude MatrixBase_colwise.out * - * \sa rowwise(), class VectorwiseOp + * \sa rowwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting */ template inline const typename DenseBase::ConstColwiseReturnType @@ -520,7 +559,7 @@ DenseBase::colwise() const /** \returns a writable VectorwiseOp wrapper of *this providing additional partial reduction operations * - * \sa rowwise(), class VectorwiseOp + * \sa rowwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting */ template inline typename DenseBase::ColwiseReturnType @@ -534,7 +573,7 @@ DenseBase::colwise() * Example: \include MatrixBase_rowwise.cpp * Output: \verbinclude MatrixBase_rowwise.out * - * \sa colwise(), class VectorwiseOp + * \sa colwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting */ template inline const typename DenseBase::ConstRowwiseReturnType @@ -545,7 +584,7 @@ DenseBase::rowwise() const /** \returns a writable VectorwiseOp wrapper of *this providing additional partial reduction operations * - * \sa colwise(), class VectorwiseOp + * \sa colwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting */ template inline typename DenseBase::RowwiseReturnType @@ -554,4 +593,6 @@ DenseBase::rowwise() return derived(); } +} // end namespace Eigen + #endif // EIGEN_PARTIAL_REDUX_H diff --git a/extern/Eigen3/Eigen/src/Core/Visitor.h b/extern/Eigen3/Eigen/src/Core/Visitor.h index 378ebcba174..916bfd096a9 100644 --- a/extern/Eigen3/Eigen/src/Core/Visitor.h +++ b/extern/Eigen3/Eigen/src/Core/Visitor.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_VISITOR_H #define EIGEN_VISITOR_H +namespace Eigen { + namespace internal { template @@ -35,7 +22,7 @@ struct visitor_impl row = (UnrollCount-1) % Derived::RowsAtCompileTime }; - inline static void run(const Derived &mat, Visitor& visitor) + static inline void run(const Derived &mat, Visitor& visitor) { visitor_impl::run(mat, visitor); visitor(mat.coeff(row, col), row, col); @@ -45,7 +32,7 @@ struct visitor_impl template struct visitor_impl { - inline static void run(const Derived &mat, Visitor& visitor) + static inline void run(const Derived &mat, Visitor& visitor) { return visitor.init(mat.coeff(0, 0), 0, 0); } @@ -55,7 +42,7 @@ template struct visitor_impl { typedef typename Derived::Index Index; - inline static void run(const Derived& mat, Visitor& visitor) + static inline void run(const Derived& mat, Visitor& visitor) { visitor.init(mat.coeff(0,0), 0, 0); for(Index i = 1; i < mat.rows(); ++i) @@ -245,4 +232,6 @@ DenseBase::maxCoeff(IndexType* index) const return maxVisitor.res; } +} // end namespace Eigen + #endif // EIGEN_VISITOR_H diff --git a/extern/Eigen3/Eigen/src/Core/arch/AltiVec/Complex.h b/extern/Eigen3/Eigen/src/Core/arch/AltiVec/Complex.h index f8adf1b6385..68d9a2bff8d 100644 --- a/extern/Eigen3/Eigen/src/Core/arch/AltiVec/Complex.h +++ b/extern/Eigen3/Eigen/src/Core/arch/AltiVec/Complex.h @@ -3,28 +3,15 @@ // // Copyright (C) 2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_COMPLEX_ALTIVEC_H #define EIGEN_COMPLEX_ALTIVEC_H +namespace Eigen { + namespace internal { static Packet4ui p4ui_CONJ_XOR = vec_mergeh((Packet4ui)p4i_ZERO, (Packet4ui)p4f_ZERO_);//{ 0x00000000, 0x80000000, 0x00000000, 0x80000000 }; @@ -168,7 +155,7 @@ template<> EIGEN_STRONG_INLINE std::complex predux_mul(const P template struct palign_impl { - EIGEN_STRONG_INLINE static void run(Packet2cf& first, const Packet2cf& second) + static EIGEN_STRONG_INLINE void run(Packet2cf& first, const Packet2cf& second) { if (Offset==1) { @@ -225,4 +212,6 @@ template<> EIGEN_STRONG_INLINE Packet2cf pcplxflip(const Packet2cf& x } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_COMPLEX_ALTIVEC_H diff --git a/extern/Eigen3/Eigen/src/Core/arch/AltiVec/PacketMath.h b/extern/Eigen3/Eigen/src/Core/arch/AltiVec/PacketMath.h index dc34ebbd660..75de1931198 100644 --- a/extern/Eigen3/Eigen/src/Core/arch/AltiVec/PacketMath.h +++ b/extern/Eigen3/Eigen/src/Core/arch/AltiVec/PacketMath.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008 Konstantinos Margaritis // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_PACKET_MATH_ALTIVEC_H #define EIGEN_PACKET_MATH_ALTIVEC_H +namespace Eigen { + namespace internal { #ifndef EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD @@ -487,7 +474,7 @@ template<> EIGEN_STRONG_INLINE int predux_max(const Packet4i& a) template struct palign_impl { - EIGEN_STRONG_INLINE static void run(Packet4f& first, const Packet4f& second) + static EIGEN_STRONG_INLINE void run(Packet4f& first, const Packet4f& second) { if (Offset!=0) first = vec_sld(first, second, Offset*4); @@ -497,7 +484,7 @@ struct palign_impl template struct palign_impl { - EIGEN_STRONG_INLINE static void run(Packet4i& first, const Packet4i& second) + static EIGEN_STRONG_INLINE void run(Packet4i& first, const Packet4i& second) { if (Offset!=0) first = vec_sld(first, second, Offset*4); @@ -506,4 +493,6 @@ struct palign_impl } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_PACKET_MATH_ALTIVEC_H diff --git a/extern/Eigen3/Eigen/src/Core/arch/Default/Settings.h b/extern/Eigen3/Eigen/src/Core/arch/Default/Settings.h index 957adc8fe42..097373c84dc 100644 --- a/extern/Eigen3/Eigen/src/Core/arch/Default/Settings.h +++ b/extern/Eigen3/Eigen/src/Core/arch/Default/Settings.h @@ -4,24 +4,9 @@ // Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. /* All the parameters defined in this file can be specialized in the diff --git a/extern/Eigen3/Eigen/src/Core/arch/NEON/Complex.h b/extern/Eigen3/Eigen/src/Core/arch/NEON/Complex.h index 212887184c2..795b4be7303 100644 --- a/extern/Eigen3/Eigen/src/Core/arch/NEON/Complex.h +++ b/extern/Eigen3/Eigen/src/Core/arch/NEON/Complex.h @@ -3,28 +3,15 @@ // // Copyright (C) 2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_COMPLEX_NEON_H #define EIGEN_COMPLEX_NEON_H +namespace Eigen { + namespace internal { static uint32x4_t p4ui_CONJ_XOR = EIGEN_INIT_NEON_PACKET4(0x00000000, 0x80000000, 0x00000000, 0x80000000); @@ -267,4 +254,6 @@ template<> EIGEN_STRONG_INLINE Packet2cf pdiv(const Packet2cf& a, con } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_COMPLEX_NEON_H diff --git a/extern/Eigen3/Eigen/src/Core/arch/NEON/PacketMath.h b/extern/Eigen3/Eigen/src/Core/arch/NEON/PacketMath.h index 6c7cd159097..a20250f7c65 100644 --- a/extern/Eigen3/Eigen/src/Core/arch/NEON/PacketMath.h +++ b/extern/Eigen3/Eigen/src/Core/arch/NEON/PacketMath.h @@ -5,28 +5,15 @@ // Copyright (C) 2010 Konstantinos Margaritis // Heavily based on Gael's SSE version. // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_PACKET_MATH_NEON_H #define EIGEN_PACKET_MATH_NEON_H +namespace Eigen { + namespace internal { #ifndef EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD @@ -158,7 +145,8 @@ template<> EIGEN_STRONG_INLINE Packet4i pdiv(const Packet4i& /*a*/, co } // for some weird raisons, it has to be overloaded for packet of integers -template<> EIGEN_STRONG_INLINE Packet4i pmadd(const Packet4i& a, const Packet4i& b, const Packet4i& c) { return padd(pmul(a,b), c); } +template<> EIGEN_STRONG_INLINE Packet4f pmadd(const Packet4f& a, const Packet4f& b, const Packet4f& c) { return vmlaq_f32(c,a,b); } +template<> EIGEN_STRONG_INLINE Packet4i pmadd(const Packet4i& a, const Packet4i& b, const Packet4i& c) { return vmlaq_s32(c,a,b); } template<> EIGEN_STRONG_INLINE Packet4f pmin(const Packet4f& a, const Packet4f& b) { return vminq_f32(a,b); } template<> EIGEN_STRONG_INLINE Packet4i pmin(const Packet4i& a, const Packet4i& b) { return vminq_s32(a,b); } @@ -431,4 +419,6 @@ PALIGN_NEON(3,Packet4i,vextq_s32) } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_PACKET_MATH_NEON_H diff --git a/extern/Eigen3/Eigen/src/Core/arch/SSE/Complex.h b/extern/Eigen3/Eigen/src/Core/arch/SSE/Complex.h index c352bb3e6cf..12df987754c 100644 --- a/extern/Eigen3/Eigen/src/Core/arch/SSE/Complex.h +++ b/extern/Eigen3/Eigen/src/Core/arch/SSE/Complex.h @@ -3,28 +3,15 @@ // // Copyright (C) 2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_COMPLEX_SSE_H #define EIGEN_COMPLEX_SSE_H +namespace Eigen { + namespace internal { //---------- float ---------- @@ -102,7 +89,7 @@ template<> EIGEN_STRONG_INLINE Packet2cf pset1(const std::complex(&from)); #else res.v = _mm_loadl_pi(res.v, (const __m64*)&from); #endif @@ -151,7 +138,7 @@ template<> EIGEN_STRONG_INLINE std::complex predux_mul(const P template struct palign_impl { - EIGEN_STRONG_INLINE static void run(Packet2cf& first, const Packet2cf& second) + static EIGEN_STRONG_INLINE void run(Packet2cf& first, const Packet2cf& second) { if (Offset==1) { @@ -350,7 +337,7 @@ template<> EIGEN_STRONG_INLINE std::complex predux_mul(const template struct palign_impl { - EIGEN_STRONG_INLINE static void run(Packet1cd& /*first*/, const Packet1cd& /*second*/) + static EIGEN_STRONG_INLINE void run(Packet1cd& /*first*/, const Packet1cd& /*second*/) { // FIXME is it sure we never have to align a Packet1cd? // Even though a std::complex has 16 bytes, it is not necessarily aligned on a 16 bytes boundary... @@ -444,4 +431,6 @@ EIGEN_STRONG_INLINE Packet1cd pcplxflip/**/(const Packet1cd& x) } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_COMPLEX_SSE_H diff --git a/extern/Eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h b/extern/Eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h index 9d56d82180b..3f41a4e2600 100644 --- a/extern/Eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h +++ b/extern/Eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h @@ -4,24 +4,9 @@ // Copyright (C) 2007 Julien Pommier // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. /* The sin, cos, exp, and log functions of this file come from * Julien Pommier's sse math library: http://gruntthepeon.free.fr/ssemath/ @@ -30,6 +15,8 @@ #ifndef EIGEN_MATH_FUNCTIONS_SSE_H #define EIGEN_MATH_FUNCTIONS_SSE_H +namespace Eigen { + namespace internal { template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED @@ -121,7 +108,7 @@ Packet4f pexp(const Packet4f& _x) _EIGEN_DECLARE_CONST_Packet4i(0x7f, 0x7f); - _EIGEN_DECLARE_CONST_Packet4f(exp_hi, 88.3762626647949f); + _EIGEN_DECLARE_CONST_Packet4f(exp_hi, 88.3762626647950f); _EIGEN_DECLARE_CONST_Packet4f(exp_lo, -88.3762626647949f); _EIGEN_DECLARE_CONST_Packet4f(cephes_LOG2EF, 1.44269504088896341f); @@ -168,7 +155,7 @@ Packet4f pexp(const Packet4f& _x) y = pmadd(y, z, x); y = padd(y, p4f_1); - /* build 2^n */ + // build 2^n emm0 = _mm_cvttps_epi32(fx); emm0 = _mm_add_epi32(emm0, p4i_0x7f); emm0 = _mm_slli_epi32(emm0, 23); @@ -392,4 +379,6 @@ Packet4f psqrt(const Packet4f& _x) } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_MATH_FUNCTIONS_SSE_H diff --git a/extern/Eigen3/Eigen/src/Core/arch/SSE/PacketMath.h b/extern/Eigen3/Eigen/src/Core/arch/SSE/PacketMath.h index 908e27368e8..10d9182190f 100644 --- a/extern/Eigen3/Eigen/src/Core/arch/SSE/PacketMath.h +++ b/extern/Eigen3/Eigen/src/Core/arch/SSE/PacketMath.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008-2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_PACKET_MATH_SSE_H #define EIGEN_PACKET_MATH_SSE_H +namespace Eigen { + namespace internal { #ifndef EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD @@ -110,9 +97,18 @@ template<> struct unpacket_traits { typedef float type; enum {size=4} template<> struct unpacket_traits { typedef double type; enum {size=2}; }; template<> struct unpacket_traits { typedef int type; enum {size=4}; }; +#if defined(_MSC_VER) && (_MSC_VER==1500) +// Workaround MSVC 9 internal compiler error. +// TODO: It has been detected with win64 builds (amd64), so let's check whether it also happens in 32bits+SSE mode +// TODO: let's check whether there does not exist a better fix, like adding a pset0() function. (it crashed on pset1(0)). +template<> EIGEN_STRONG_INLINE Packet4f pset1(const float& from) { return _mm_set_ps(from,from,from,from); } +template<> EIGEN_STRONG_INLINE Packet2d pset1(const double& from) { return _mm_set_pd(from,from); } +template<> EIGEN_STRONG_INLINE Packet4i pset1(const int& from) { return _mm_set_epi32(from,from,from,from); } +#else template<> EIGEN_STRONG_INLINE Packet4f pset1(const float& from) { return _mm_set1_ps(from); } template<> EIGEN_STRONG_INLINE Packet2d pset1(const double& from) { return _mm_set1_pd(from); } template<> EIGEN_STRONG_INLINE Packet4i pset1(const int& from) { return _mm_set1_epi32(from); } +#endif template<> EIGEN_STRONG_INLINE Packet4f plset(const float& a) { return _mm_add_ps(pset1(a), _mm_set_ps(3,2,1,0)); } template<> EIGEN_STRONG_INLINE Packet2d plset(const double& a) { return _mm_add_pd(pset1(a),_mm_set_pd(1,0)); } @@ -282,7 +278,7 @@ template<> EIGEN_STRONG_INLINE Packet4i ploadu(const int* from) template<> EIGEN_STRONG_INLINE Packet4f ploaddup(const float* from) { - return vec4f_swizzle1(_mm_castpd_ps(_mm_load_sd((const double*)from)), 0, 0, 1, 1); + return vec4f_swizzle1(_mm_castpd_ps(_mm_load_sd(reinterpret_cast(from))), 0, 0, 1, 1); } template<> EIGEN_STRONG_INLINE Packet2d ploaddup(const double* from) { return pset1(from[0]); } @@ -302,8 +298,8 @@ template<> EIGEN_STRONG_INLINE void pstoreu(double* to, const Packet2d& _mm_storel_pd((to), from); _mm_storeh_pd((to+1), from); } -template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet4f& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, _mm_castps_pd(from)); } -template<> EIGEN_STRONG_INLINE void pstoreu(int* to, const Packet4i& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, _mm_castsi128_pd(from)); } +template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet4f& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu(reinterpret_cast(to), _mm_castps_pd(from)); } +template<> EIGEN_STRONG_INLINE void pstoreu(int* to, const Packet4i& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu(reinterpret_cast(to), _mm_castsi128_pd(from)); } // some compilers might be tempted to perform multiple moves instead of using a vector path. template<> EIGEN_STRONG_INLINE void pstore1(float* to, const float& a) @@ -541,7 +537,7 @@ template<> EIGEN_STRONG_INLINE int predux_max(const Packet4i& a) template struct palign_impl { - EIGEN_STRONG_INLINE static void run(Packet4f& first, const Packet4f& second) + static EIGEN_STRONG_INLINE void run(Packet4f& first, const Packet4f& second) { if (Offset!=0) first = _mm_castsi128_ps(_mm_alignr_epi8(_mm_castps_si128(second), _mm_castps_si128(first), Offset*4)); @@ -551,7 +547,7 @@ struct palign_impl template struct palign_impl { - EIGEN_STRONG_INLINE static void run(Packet4i& first, const Packet4i& second) + static EIGEN_STRONG_INLINE void run(Packet4i& first, const Packet4i& second) { if (Offset!=0) first = _mm_alignr_epi8(second,first, Offset*4); @@ -561,7 +557,7 @@ struct palign_impl template struct palign_impl { - EIGEN_STRONG_INLINE static void run(Packet2d& first, const Packet2d& second) + static EIGEN_STRONG_INLINE void run(Packet2d& first, const Packet2d& second) { if (Offset==1) first = _mm_castsi128_pd(_mm_alignr_epi8(_mm_castpd_si128(second), _mm_castpd_si128(first), 8)); @@ -572,7 +568,7 @@ struct palign_impl template struct palign_impl { - EIGEN_STRONG_INLINE static void run(Packet4f& first, const Packet4f& second) + static EIGEN_STRONG_INLINE void run(Packet4f& first, const Packet4f& second) { if (Offset==1) { @@ -595,7 +591,7 @@ struct palign_impl template struct palign_impl { - EIGEN_STRONG_INLINE static void run(Packet4i& first, const Packet4i& second) + static EIGEN_STRONG_INLINE void run(Packet4i& first, const Packet4i& second) { if (Offset==1) { @@ -618,7 +614,7 @@ struct palign_impl template struct palign_impl { - EIGEN_STRONG_INLINE static void run(Packet2d& first, const Packet2d& second) + static EIGEN_STRONG_INLINE void run(Packet2d& first, const Packet2d& second) { if (Offset==1) { @@ -631,4 +627,6 @@ struct palign_impl } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_PACKET_MATH_SSE_H diff --git a/extern/Eigen3/Eigen/src/Core/products/CoeffBasedProduct.h b/extern/Eigen3/Eigen/src/Core/products/CoeffBasedProduct.h index dc20f7e1e29..403d25fa9eb 100644 --- a/extern/Eigen3/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/extern/Eigen3/Eigen/src/Core/products/CoeffBasedProduct.h @@ -4,28 +4,15 @@ // Copyright (C) 2006-2008 Benoit Jacob // Copyright (C) 2008-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_COEFFBASED_PRODUCT_H #define EIGEN_COEFFBASED_PRODUCT_H +namespace Eigen { + namespace internal { /********************************************************************************* @@ -224,8 +211,8 @@ class CoeffBasedProduct { return reinterpret_cast(*this).diagonal(index); } protected: - const LhsNested m_lhs; - const RhsNested m_rhs; + typename internal::add_const_on_value_type::type m_lhs; + typename internal::add_const_on_value_type::type m_rhs; mutable PlainObject m_result; }; @@ -252,7 +239,7 @@ template struct product_coeff_impl { typedef typename Lhs::Index Index; - EIGEN_STRONG_INLINE static void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) { product_coeff_impl::run(row, col, lhs, rhs, res); res += lhs.coeff(row, UnrollingIndex) * rhs.coeff(UnrollingIndex, col); @@ -263,7 +250,7 @@ template struct product_coeff_impl { typedef typename Lhs::Index Index; - EIGEN_STRONG_INLINE static void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) { res = lhs.coeff(row, 0) * rhs.coeff(0, col); } @@ -273,7 +260,7 @@ template struct product_coeff_impl { typedef typename Lhs::Index Index; - EIGEN_STRONG_INLINE static void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar& res) + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar& res) { eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix"); res = lhs.coeff(row, 0) * rhs.coeff(0, col); @@ -291,7 +278,7 @@ struct product_coeff_vectorized_unroller { typedef typename Lhs::Index Index; enum { PacketSize = packet_traits::size }; - EIGEN_STRONG_INLINE static void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::PacketScalar &pres) + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::PacketScalar &pres) { product_coeff_vectorized_unroller::run(row, col, lhs, rhs, pres); pres = padd(pres, pmul( lhs.template packet(row, UnrollingIndex) , rhs.template packet(UnrollingIndex, col) )); @@ -302,7 +289,7 @@ template struct product_coeff_vectorized_unroller<0, Lhs, Rhs, Packet> { typedef typename Lhs::Index Index; - EIGEN_STRONG_INLINE static void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::PacketScalar &pres) + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::PacketScalar &pres) { pres = pmul(lhs.template packet(row, 0) , rhs.template packet(0, col)); } @@ -314,7 +301,7 @@ struct product_coeff_impl::size }; - EIGEN_STRONG_INLINE static void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) { Packet pres; product_coeff_vectorized_unroller::run(row, col, lhs, rhs, pres); @@ -327,7 +314,7 @@ template struct product_coeff_vectorized_dyn_selector { typedef typename Lhs::Index Index; - EIGEN_STRONG_INLINE static void run(Index /*row*/, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) + static EIGEN_STRONG_INLINE void run(Index /*row*/, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) { res = lhs.transpose().cwiseProduct(rhs.col(col)).sum(); } @@ -349,7 +336,7 @@ template struct product_coeff_vectorized_dyn_selector { typedef typename Lhs::Index Index; - EIGEN_STRONG_INLINE static void run(Index row, Index /*col*/, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) + static EIGEN_STRONG_INLINE void run(Index row, Index /*col*/, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) { res = lhs.row(row).transpose().cwiseProduct(rhs).sum(); } @@ -359,7 +346,7 @@ template struct product_coeff_vectorized_dyn_selector { typedef typename Lhs::Index Index; - EIGEN_STRONG_INLINE static void run(Index /*row*/, Index /*col*/, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) + static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) { res = lhs.transpose().cwiseProduct(rhs).sum(); } @@ -369,7 +356,7 @@ template struct product_coeff_impl { typedef typename Lhs::Index Index; - EIGEN_STRONG_INLINE static void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) { product_coeff_vectorized_dyn_selector::run(row, col, lhs, rhs, res); } @@ -383,7 +370,7 @@ template { typedef typename Lhs::Index Index; - EIGEN_STRONG_INLINE static void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) { product_packet_impl::run(row, col, lhs, rhs, res); res = pmadd(pset1(lhs.coeff(row, UnrollingIndex)), rhs.template packet(UnrollingIndex, col), res); @@ -394,7 +381,7 @@ template { typedef typename Lhs::Index Index; - EIGEN_STRONG_INLINE static void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) { product_packet_impl::run(row, col, lhs, rhs, res); res = pmadd(lhs.template packet(row, UnrollingIndex), pset1(rhs.coeff(UnrollingIndex, col)), res); @@ -405,7 +392,7 @@ template struct product_packet_impl { typedef typename Lhs::Index Index; - EIGEN_STRONG_INLINE static void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) { res = pmul(pset1(lhs.coeff(row, 0)),rhs.template packet(0, col)); } @@ -415,7 +402,7 @@ template struct product_packet_impl { typedef typename Lhs::Index Index; - EIGEN_STRONG_INLINE static void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) { res = pmul(lhs.template packet(row, 0), pset1(rhs.coeff(0, col))); } @@ -425,7 +412,7 @@ template struct product_packet_impl { typedef typename Lhs::Index Index; - EIGEN_STRONG_INLINE static void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res) + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res) { eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix"); res = pmul(pset1(lhs.coeff(row, 0)),rhs.template packet(0, col)); @@ -438,7 +425,7 @@ template struct product_packet_impl { typedef typename Lhs::Index Index; - EIGEN_STRONG_INLINE static void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res) + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res) { eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix"); res = pmul(lhs.template packet(row, 0), pset1(rhs.coeff(0, col))); @@ -449,4 +436,6 @@ struct product_packet_impl } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_COEFFBASED_PRODUCT_H diff --git a/extern/Eigen3/Eigen/src/Core/products/GeneralBlockPanelKernel.h b/extern/Eigen3/Eigen/src/Core/products/GeneralBlockPanelKernel.h index cd1c37c780e..5eb03c98ccf 100644 --- a/extern/Eigen3/Eigen/src/Core/products/GeneralBlockPanelKernel.h +++ b/extern/Eigen3/Eigen/src/Core/products/GeneralBlockPanelKernel.h @@ -3,34 +3,23 @@ // // Copyright (C) 2008-2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_GENERAL_BLOCK_PANEL_H #define EIGEN_GENERAL_BLOCK_PANEL_H +namespace Eigen { + namespace internal { template class gebp_traits; -inline std::ptrdiff_t manage_caching_sizes_second_if_negative(std::ptrdiff_t a, std::ptrdiff_t b) + +/** \internal \returns b if a<=0, and returns a otherwise. */ +inline std::ptrdiff_t manage_caching_sizes_helper(std::ptrdiff_t a, std::ptrdiff_t b) { return a<=0 ? b : a; } @@ -38,9 +27,14 @@ inline std::ptrdiff_t manage_caching_sizes_second_if_negative(std::ptrdiff_t a, /** \internal */ inline void manage_caching_sizes(Action action, std::ptrdiff_t* l1=0, std::ptrdiff_t* l2=0) { - static std::ptrdiff_t m_l1CacheSize = manage_caching_sizes_second_if_negative(queryL1CacheSize(),8 * 1024); - static std::ptrdiff_t m_l2CacheSize = manage_caching_sizes_second_if_negative(queryTopLevelCacheSize(),1*1024*1024); - + static std::ptrdiff_t m_l1CacheSize = 0; + static std::ptrdiff_t m_l2CacheSize = 0; + if(m_l2CacheSize==0) + { + m_l1CacheSize = manage_caching_sizes_helper(queryL1CacheSize(),8 * 1024); + m_l2CacheSize = manage_caching_sizes_helper(queryTopLevelCacheSize(),1*1024*1024); + } + if(action==SetAction) { // set the cpu cache size and cache all block sizes from a global cache size in byte @@ -533,7 +527,7 @@ struct gebp_kernel ResPacketSize = Traits::ResPacketSize }; - EIGEN_FLATTEN_ATTRIB + EIGEN_DONT_INLINE EIGEN_FLATTEN_ATTRIB void operator()(ResScalar* res, Index resStride, const LhsScalar* blockA, const RhsScalar* blockB, Index rows, Index depth, Index cols, ResScalar alpha, Index strideA=-1, Index strideB=-1, Index offsetA=0, Index offsetB=0, RhsScalar* unpackedB = 0) { @@ -595,64 +589,64 @@ struct gebp_kernel if(nr==2) { LhsPacket A0, A1; - RhsPacket B0; + RhsPacket B_0; RhsPacket T0; EIGEN_ASM_COMMENT("mybegin2"); traits.loadLhs(&blA[0*LhsProgress], A0); traits.loadLhs(&blA[1*LhsProgress], A1); - traits.loadRhs(&blB[0*RhsProgress], B0); - traits.madd(A0,B0,C0,T0); - traits.madd(A1,B0,C4,B0); - traits.loadRhs(&blB[1*RhsProgress], B0); - traits.madd(A0,B0,C1,T0); - traits.madd(A1,B0,C5,B0); + traits.loadRhs(&blB[0*RhsProgress], B_0); + traits.madd(A0,B_0,C0,T0); + traits.madd(A1,B_0,C4,B_0); + traits.loadRhs(&blB[1*RhsProgress], B_0); + traits.madd(A0,B_0,C1,T0); + traits.madd(A1,B_0,C5,B_0); traits.loadLhs(&blA[2*LhsProgress], A0); traits.loadLhs(&blA[3*LhsProgress], A1); - traits.loadRhs(&blB[2*RhsProgress], B0); - traits.madd(A0,B0,C0,T0); - traits.madd(A1,B0,C4,B0); - traits.loadRhs(&blB[3*RhsProgress], B0); - traits.madd(A0,B0,C1,T0); - traits.madd(A1,B0,C5,B0); + traits.loadRhs(&blB[2*RhsProgress], B_0); + traits.madd(A0,B_0,C0,T0); + traits.madd(A1,B_0,C4,B_0); + traits.loadRhs(&blB[3*RhsProgress], B_0); + traits.madd(A0,B_0,C1,T0); + traits.madd(A1,B_0,C5,B_0); traits.loadLhs(&blA[4*LhsProgress], A0); traits.loadLhs(&blA[5*LhsProgress], A1); - traits.loadRhs(&blB[4*RhsProgress], B0); - traits.madd(A0,B0,C0,T0); - traits.madd(A1,B0,C4,B0); - traits.loadRhs(&blB[5*RhsProgress], B0); - traits.madd(A0,B0,C1,T0); - traits.madd(A1,B0,C5,B0); + traits.loadRhs(&blB[4*RhsProgress], B_0); + traits.madd(A0,B_0,C0,T0); + traits.madd(A1,B_0,C4,B_0); + traits.loadRhs(&blB[5*RhsProgress], B_0); + traits.madd(A0,B_0,C1,T0); + traits.madd(A1,B_0,C5,B_0); traits.loadLhs(&blA[6*LhsProgress], A0); traits.loadLhs(&blA[7*LhsProgress], A1); - traits.loadRhs(&blB[6*RhsProgress], B0); - traits.madd(A0,B0,C0,T0); - traits.madd(A1,B0,C4,B0); - traits.loadRhs(&blB[7*RhsProgress], B0); - traits.madd(A0,B0,C1,T0); - traits.madd(A1,B0,C5,B0); + traits.loadRhs(&blB[6*RhsProgress], B_0); + traits.madd(A0,B_0,C0,T0); + traits.madd(A1,B_0,C4,B_0); + traits.loadRhs(&blB[7*RhsProgress], B_0); + traits.madd(A0,B_0,C1,T0); + traits.madd(A1,B_0,C5,B_0); EIGEN_ASM_COMMENT("myend"); } else { EIGEN_ASM_COMMENT("mybegin4"); LhsPacket A0, A1; - RhsPacket B0, B1, B2, B3; + RhsPacket B_0, B1, B2, B3; RhsPacket T0; traits.loadLhs(&blA[0*LhsProgress], A0); traits.loadLhs(&blA[1*LhsProgress], A1); - traits.loadRhs(&blB[0*RhsProgress], B0); + traits.loadRhs(&blB[0*RhsProgress], B_0); traits.loadRhs(&blB[1*RhsProgress], B1); - traits.madd(A0,B0,C0,T0); + traits.madd(A0,B_0,C0,T0); traits.loadRhs(&blB[2*RhsProgress], B2); - traits.madd(A1,B0,C4,B0); + traits.madd(A1,B_0,C4,B_0); traits.loadRhs(&blB[3*RhsProgress], B3); - traits.loadRhs(&blB[4*RhsProgress], B0); + traits.loadRhs(&blB[4*RhsProgress], B_0); traits.madd(A0,B1,C1,T0); traits.madd(A1,B1,C5,B1); traits.loadRhs(&blB[5*RhsProgress], B1); @@ -664,9 +658,9 @@ EIGEN_ASM_COMMENT("mybegin4"); traits.madd(A1,B3,C7,B3); traits.loadLhs(&blA[3*LhsProgress], A1); traits.loadRhs(&blB[7*RhsProgress], B3); - traits.madd(A0,B0,C0,T0); - traits.madd(A1,B0,C4,B0); - traits.loadRhs(&blB[8*RhsProgress], B0); + traits.madd(A0,B_0,C0,T0); + traits.madd(A1,B_0,C4,B_0); + traits.loadRhs(&blB[8*RhsProgress], B_0); traits.madd(A0,B1,C1,T0); traits.madd(A1,B1,C5,B1); traits.loadRhs(&blB[9*RhsProgress], B1); @@ -679,9 +673,9 @@ EIGEN_ASM_COMMENT("mybegin4"); traits.loadLhs(&blA[5*LhsProgress], A1); traits.loadRhs(&blB[11*RhsProgress], B3); - traits.madd(A0,B0,C0,T0); - traits.madd(A1,B0,C4,B0); - traits.loadRhs(&blB[12*RhsProgress], B0); + traits.madd(A0,B_0,C0,T0); + traits.madd(A1,B_0,C4,B_0); + traits.loadRhs(&blB[12*RhsProgress], B_0); traits.madd(A0,B1,C1,T0); traits.madd(A1,B1,C5,B1); traits.loadRhs(&blB[13*RhsProgress], B1); @@ -693,8 +687,8 @@ EIGEN_ASM_COMMENT("mybegin4"); traits.madd(A1,B3,C7,B3); traits.loadLhs(&blA[7*LhsProgress], A1); traits.loadRhs(&blB[15*RhsProgress], B3); - traits.madd(A0,B0,C0,T0); - traits.madd(A1,B0,C4,B0); + traits.madd(A0,B_0,C0,T0); + traits.madd(A1,B_0,C4,B_0); traits.madd(A0,B1,C1,T0); traits.madd(A1,B1,C5,B1); traits.madd(A0,B2,C2,T0); @@ -712,32 +706,32 @@ EIGEN_ASM_COMMENT("mybegin4"); if(nr==2) { LhsPacket A0, A1; - RhsPacket B0; + RhsPacket B_0; RhsPacket T0; traits.loadLhs(&blA[0*LhsProgress], A0); traits.loadLhs(&blA[1*LhsProgress], A1); - traits.loadRhs(&blB[0*RhsProgress], B0); - traits.madd(A0,B0,C0,T0); - traits.madd(A1,B0,C4,B0); - traits.loadRhs(&blB[1*RhsProgress], B0); - traits.madd(A0,B0,C1,T0); - traits.madd(A1,B0,C5,B0); + traits.loadRhs(&blB[0*RhsProgress], B_0); + traits.madd(A0,B_0,C0,T0); + traits.madd(A1,B_0,C4,B_0); + traits.loadRhs(&blB[1*RhsProgress], B_0); + traits.madd(A0,B_0,C1,T0); + traits.madd(A1,B_0,C5,B_0); } else { LhsPacket A0, A1; - RhsPacket B0, B1, B2, B3; + RhsPacket B_0, B1, B2, B3; RhsPacket T0; traits.loadLhs(&blA[0*LhsProgress], A0); traits.loadLhs(&blA[1*LhsProgress], A1); - traits.loadRhs(&blB[0*RhsProgress], B0); + traits.loadRhs(&blB[0*RhsProgress], B_0); traits.loadRhs(&blB[1*RhsProgress], B1); - traits.madd(A0,B0,C0,T0); + traits.madd(A0,B_0,C0,T0); traits.loadRhs(&blB[2*RhsProgress], B2); - traits.madd(A1,B0,C4,B0); + traits.madd(A1,B_0,C4,B_0); traits.loadRhs(&blB[3*RhsProgress], B3); traits.madd(A0,B1,C1,T0); traits.madd(A1,B1,C5,B1); @@ -824,42 +818,42 @@ EIGEN_ASM_COMMENT("mybegin4"); if(nr==2) { LhsPacket A0; - RhsPacket B0, B1; + RhsPacket B_0, B1; traits.loadLhs(&blA[0*LhsProgress], A0); - traits.loadRhs(&blB[0*RhsProgress], B0); + traits.loadRhs(&blB[0*RhsProgress], B_0); traits.loadRhs(&blB[1*RhsProgress], B1); - traits.madd(A0,B0,C0,B0); - traits.loadRhs(&blB[2*RhsProgress], B0); + traits.madd(A0,B_0,C0,B_0); + traits.loadRhs(&blB[2*RhsProgress], B_0); traits.madd(A0,B1,C1,B1); traits.loadLhs(&blA[1*LhsProgress], A0); traits.loadRhs(&blB[3*RhsProgress], B1); - traits.madd(A0,B0,C0,B0); - traits.loadRhs(&blB[4*RhsProgress], B0); + traits.madd(A0,B_0,C0,B_0); + traits.loadRhs(&blB[4*RhsProgress], B_0); traits.madd(A0,B1,C1,B1); traits.loadLhs(&blA[2*LhsProgress], A0); traits.loadRhs(&blB[5*RhsProgress], B1); - traits.madd(A0,B0,C0,B0); - traits.loadRhs(&blB[6*RhsProgress], B0); + traits.madd(A0,B_0,C0,B_0); + traits.loadRhs(&blB[6*RhsProgress], B_0); traits.madd(A0,B1,C1,B1); traits.loadLhs(&blA[3*LhsProgress], A0); traits.loadRhs(&blB[7*RhsProgress], B1); - traits.madd(A0,B0,C0,B0); + traits.madd(A0,B_0,C0,B_0); traits.madd(A0,B1,C1,B1); } else { LhsPacket A0; - RhsPacket B0, B1, B2, B3; + RhsPacket B_0, B1, B2, B3; traits.loadLhs(&blA[0*LhsProgress], A0); - traits.loadRhs(&blB[0*RhsProgress], B0); + traits.loadRhs(&blB[0*RhsProgress], B_0); traits.loadRhs(&blB[1*RhsProgress], B1); - traits.madd(A0,B0,C0,B0); + traits.madd(A0,B_0,C0,B_0); traits.loadRhs(&blB[2*RhsProgress], B2); traits.loadRhs(&blB[3*RhsProgress], B3); - traits.loadRhs(&blB[4*RhsProgress], B0); + traits.loadRhs(&blB[4*RhsProgress], B_0); traits.madd(A0,B1,C1,B1); traits.loadRhs(&blB[5*RhsProgress], B1); traits.madd(A0,B2,C2,B2); @@ -867,8 +861,8 @@ EIGEN_ASM_COMMENT("mybegin4"); traits.madd(A0,B3,C3,B3); traits.loadLhs(&blA[1*LhsProgress], A0); traits.loadRhs(&blB[7*RhsProgress], B3); - traits.madd(A0,B0,C0,B0); - traits.loadRhs(&blB[8*RhsProgress], B0); + traits.madd(A0,B_0,C0,B_0); + traits.loadRhs(&blB[8*RhsProgress], B_0); traits.madd(A0,B1,C1,B1); traits.loadRhs(&blB[9*RhsProgress], B1); traits.madd(A0,B2,C2,B2); @@ -877,8 +871,8 @@ EIGEN_ASM_COMMENT("mybegin4"); traits.loadLhs(&blA[2*LhsProgress], A0); traits.loadRhs(&blB[11*RhsProgress], B3); - traits.madd(A0,B0,C0,B0); - traits.loadRhs(&blB[12*RhsProgress], B0); + traits.madd(A0,B_0,C0,B_0); + traits.loadRhs(&blB[12*RhsProgress], B_0); traits.madd(A0,B1,C1,B1); traits.loadRhs(&blB[13*RhsProgress], B1); traits.madd(A0,B2,C2,B2); @@ -887,7 +881,7 @@ EIGEN_ASM_COMMENT("mybegin4"); traits.loadLhs(&blA[3*LhsProgress], A0); traits.loadRhs(&blB[15*RhsProgress], B3); - traits.madd(A0,B0,C0,B0); + traits.madd(A0,B_0,C0,B_0); traits.madd(A0,B1,C1,B1); traits.madd(A0,B2,C2,B2); traits.madd(A0,B3,C3,B3); @@ -902,26 +896,26 @@ EIGEN_ASM_COMMENT("mybegin4"); if(nr==2) { LhsPacket A0; - RhsPacket B0, B1; + RhsPacket B_0, B1; traits.loadLhs(&blA[0*LhsProgress], A0); - traits.loadRhs(&blB[0*RhsProgress], B0); + traits.loadRhs(&blB[0*RhsProgress], B_0); traits.loadRhs(&blB[1*RhsProgress], B1); - traits.madd(A0,B0,C0,B0); + traits.madd(A0,B_0,C0,B_0); traits.madd(A0,B1,C1,B1); } else { LhsPacket A0; - RhsPacket B0, B1, B2, B3; + RhsPacket B_0, B1, B2, B3; traits.loadLhs(&blA[0*LhsProgress], A0); - traits.loadRhs(&blB[0*RhsProgress], B0); + traits.loadRhs(&blB[0*RhsProgress], B_0); traits.loadRhs(&blB[1*RhsProgress], B1); traits.loadRhs(&blB[2*RhsProgress], B2); traits.loadRhs(&blB[3*RhsProgress], B3); - traits.madd(A0,B0,C0,B0); + traits.madd(A0,B_0,C0,B_0); traits.madd(A0,B1,C1,B1); traits.madd(A0,B2,C2,B2); traits.madd(A0,B3,C3,B3); @@ -968,26 +962,26 @@ EIGEN_ASM_COMMENT("mybegin4"); if(nr==2) { LhsScalar A0; - RhsScalar B0, B1; + RhsScalar B_0, B1; A0 = blA[k]; - B0 = blB[0]; + B_0 = blB[0]; B1 = blB[1]; - MADD(cj,A0,B0,C0,B0); + MADD(cj,A0,B_0,C0,B_0); MADD(cj,A0,B1,C1,B1); } else { LhsScalar A0; - RhsScalar B0, B1, B2, B3; + RhsScalar B_0, B1, B2, B3; A0 = blA[k]; - B0 = blB[0]; + B_0 = blB[0]; B1 = blB[1]; B2 = blB[2]; B3 = blB[3]; - MADD(cj,A0,B0,C0,B0); + MADD(cj,A0,B_0,C0,B_0); MADD(cj,A0,B1,C1,B1); MADD(cj,A0,B2,C2,B2); MADD(cj,A0,B3,C3,B3); @@ -1024,14 +1018,14 @@ EIGEN_ASM_COMMENT("mybegin4"); for(Index k=0; k struct gemm_pack_lhs { - void operator()(Scalar* blockA, const Scalar* EIGEN_RESTRICT _lhs, Index lhsStride, Index depth, Index rows, + EIGEN_DONT_INLINE void operator()(Scalar* blockA, const Scalar* EIGEN_RESTRICT _lhs, Index lhsStride, Index depth, Index rows, Index stride=0, Index offset=0) { -// enum { PacketSize = packet_traits::size }; + typedef typename packet_traits::type Packet; + enum { PacketSize = packet_traits::size }; + + EIGEN_ASM_COMMENT("EIGEN PRODUCT PACK LHS"); eigen_assert(((!PanelMode) && stride==0 && offset==0) || (PanelMode && stride>=depth && offset<=stride)); + eigen_assert( (StorageOrder==RowMajor) || ((Pack1%PacketSize)==0 && Pack1<=4*PacketSize) ); conj_if::IsComplex && Conjugate> cj; const_blas_data_mapper lhs(_lhs,lhsStride); Index count = 0; @@ -1128,9 +1126,44 @@ struct gemm_pack_lhs for(Index i=0; i=1*PacketSize) A = ploadu(&lhs(i+0*PacketSize, k)); + if(Pack1>=2*PacketSize) B = ploadu(&lhs(i+1*PacketSize, k)); + if(Pack1>=3*PacketSize) C = ploadu(&lhs(i+2*PacketSize, k)); + if(Pack1>=4*PacketSize) D = ploadu(&lhs(i+3*PacketSize, k)); + if(Pack1>=1*PacketSize) { pstore(blockA+count, cj.pconj(A)); count+=PacketSize; } + if(Pack1>=2*PacketSize) { pstore(blockA+count, cj.pconj(B)); count+=PacketSize; } + if(Pack1>=3*PacketSize) { pstore(blockA+count, cj.pconj(C)); count+=PacketSize; } + if(Pack1>=4*PacketSize) { pstore(blockA+count, cj.pconj(D)); count+=PacketSize; } + } + } + else + { + for(Index k=0; k=Pack2) @@ -1164,9 +1197,10 @@ struct gemm_pack_rhs { typedef typename packet_traits::type Packet; enum { PacketSize = packet_traits::size }; - void operator()(Scalar* blockB, const Scalar* rhs, Index rhsStride, Index depth, Index cols, + EIGEN_DONT_INLINE void operator()(Scalar* blockB, const Scalar* rhs, Index rhsStride, Index depth, Index cols, Index stride=0, Index offset=0) { + EIGEN_ASM_COMMENT("EIGEN PRODUCT PACK RHS COLMAJOR"); eigen_assert(((!PanelMode) && stride==0 && offset==0) || (PanelMode && stride>=depth && offset<=stride)); conj_if::IsComplex && Conjugate> cj; Index packet_cols = (cols/nr) * nr; @@ -1211,9 +1245,10 @@ template { enum { PacketSize = packet_traits::size }; - void operator()(Scalar* blockB, const Scalar* rhs, Index rhsStride, Index depth, Index cols, + EIGEN_DONT_INLINE void operator()(Scalar* blockB, const Scalar* rhs, Index rhsStride, Index depth, Index cols, Index stride=0, Index offset=0) { + EIGEN_ASM_COMMENT("EIGEN PRODUCT PACK RHS ROWMAJOR"); eigen_assert(((!PanelMode) && stride==0 && offset==0) || (PanelMode && stride>=depth && offset<=stride)); conj_if::IsComplex && Conjugate> cj; Index packet_cols = (cols/nr) * nr; @@ -1279,4 +1314,6 @@ inline void setCpuCacheSizes(std::ptrdiff_t l1, std::ptrdiff_t l2) internal::manage_caching_sizes(SetAction, &l1, &l2); } +} // end namespace Eigen + #endif // EIGEN_GENERAL_BLOCK_PANEL_H diff --git a/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h b/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h index ae94a27953b..73a465ec5ee 100644 --- a/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008-2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_GENERAL_MATRIX_MATRIX_H #define EIGEN_GENERAL_MATRIX_MATRIX_H +namespace Eigen { + namespace internal { template class level3_blocking; @@ -77,7 +64,7 @@ static void run(Index rows, Index cols, Index depth, typedef gebp_traits Traits; - Index kc = blocking.kc(); // cache block size along the K direction + Index kc = blocking.kc(); // cache block size along the K direction Index mc = (std::min)(rows,blocking.mc()); // cache block size along the M direction //Index nc = blocking.nc(); // cache block size along the N direction @@ -247,7 +234,7 @@ struct gemm_functor BlockingType& m_blocking; }; -template class gemm_blocking_space; template @@ -280,8 +267,8 @@ class level3_blocking inline RhsScalar* blockW() { return m_blockW; } }; -template -class gemm_blocking_space +template +class gemm_blocking_space : public level3_blocking< typename conditional::type, typename conditional::type> @@ -322,8 +309,8 @@ class gemm_blocking_space -class gemm_blocking_space +template +class gemm_blocking_space : public level3_blocking< typename conditional::type, typename conditional::type> @@ -347,7 +334,7 @@ class gemm_blocking_spacem_nc = Transpose ? rows : cols; this->m_kc = depth; - computeProductBlockingSizes(this->m_kc, this->m_mc, this->m_nc); + computeProductBlockingSizes(this->m_kc, this->m_mc, this->m_nc); m_sizeA = this->m_mc * this->m_kc; m_sizeB = this->m_kc * this->m_nc; m_sizeW = this->m_kc*Traits::WorkSpaceFactor; @@ -412,8 +399,8 @@ class GeneralProduct { eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); - const ActualLhsType lhs = LhsBlasTraits::extract(m_lhs); - const ActualRhsType rhs = RhsBlasTraits::extract(m_rhs); + typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(m_lhs); + typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(m_rhs); Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(m_lhs) * RhsBlasTraits::extractScalarFactor(m_rhs); @@ -436,4 +423,6 @@ class GeneralProduct } }; +} // end namespace Eigen + #endif // EIGEN_GENERAL_MATRIX_MATRIX_H diff --git a/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h b/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h index 5043b64fe2e..432d3a9dc84 100644 --- a/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h +++ b/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_H #define EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_H +namespace Eigen { + namespace internal { /********************************************************************** @@ -42,14 +29,14 @@ struct tribb_kernel; template + int ResStorageOrder, int UpLo, int Version = Specialized> struct general_matrix_matrix_triangular_product; // as usual if the result is row major => we transpose the product template -struct general_matrix_matrix_triangular_product -{ + typename RhsScalar, int RhsStorageOrder, bool ConjugateRhs, int UpLo, int Version> +struct general_matrix_matrix_triangular_product +{ typedef typename scalar_product_traits::ReturnType ResScalar; static EIGEN_STRONG_INLINE void run(Index size, Index depth,const LhsScalar* lhs, Index lhsStride, const RhsScalar* rhs, Index rhsStride, ResScalar* res, Index resStride, ResScalar alpha) @@ -63,8 +50,8 @@ struct general_matrix_matrix_triangular_product -struct general_matrix_matrix_triangular_product + typename RhsScalar, int RhsStorageOrder, bool ConjugateRhs, int UpLo, int Version> +struct general_matrix_matrix_triangular_product { typedef typename scalar_product_traits::ReturnType ResScalar; static EIGEN_STRONG_INLINE void run(Index size, Index depth,const LhsScalar* _lhs, Index lhsStride, @@ -201,13 +188,13 @@ TriangularView& TriangularView::assignProduct( typedef internal::blas_traits LhsBlasTraits; typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhs; typedef typename internal::remove_all::type _ActualLhs; - const ActualLhs actualLhs = LhsBlasTraits::extract(prod.lhs()); + typename internal::add_const_on_value_type::type actualLhs = LhsBlasTraits::extract(prod.lhs()); typedef typename internal::remove_all::type Rhs; typedef internal::blas_traits RhsBlasTraits; typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhs; typedef typename internal::remove_all::type _ActualRhs; - const ActualRhs actualRhs = RhsBlasTraits::extract(prod.rhs()); + typename internal::add_const_on_value_type::type actualRhs = RhsBlasTraits::extract(prod.rhs()); typename ProductDerived::Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs().derived()) * RhsBlasTraits::extractScalarFactor(prod.rhs().derived()); @@ -222,4 +209,6 @@ TriangularView& TriangularView::assignProduct( return *this; } +} // end namespace Eigen + #endif // EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_H diff --git a/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h b/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h new file mode 100644 index 00000000000..3deed068e39 --- /dev/null +++ b/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h @@ -0,0 +1,146 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * Level 3 BLAS SYRK/HERK implementation. + ******************************************************************************** +*/ + +#ifndef EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_MKL_H +#define EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_MKL_H + +namespace Eigen { + +namespace internal { + +template +struct general_matrix_matrix_rankupdate : + general_matrix_matrix_triangular_product< + Index,Scalar,AStorageOrder,ConjugateA,Scalar,AStorageOrder,ConjugateA,ResStorageOrder,UpLo,BuiltIn> {}; + + +// try to go to BLAS specialization +#define EIGEN_MKL_RANKUPDATE_SPECIALIZE(Scalar) \ +template \ +struct general_matrix_matrix_triangular_product { \ + static EIGEN_STRONG_INLINE void run(Index size, Index depth,const Scalar* lhs, Index lhsStride, \ + const Scalar* rhs, Index rhsStride, Scalar* res, Index resStride, Scalar alpha) \ + { \ + if (lhs==rhs) { \ + general_matrix_matrix_rankupdate \ + ::run(size,depth,lhs,lhsStride,rhs,rhsStride,res,resStride,alpha); \ + } else { \ + general_matrix_matrix_triangular_product \ + ::run(size,depth,lhs,lhsStride,rhs,rhsStride,res,resStride,alpha); \ + } \ + } \ +}; + +EIGEN_MKL_RANKUPDATE_SPECIALIZE(double) +//EIGEN_MKL_RANKUPDATE_SPECIALIZE(dcomplex) +EIGEN_MKL_RANKUPDATE_SPECIALIZE(float) +//EIGEN_MKL_RANKUPDATE_SPECIALIZE(scomplex) + +// SYRK for float/double +#define EIGEN_MKL_RANKUPDATE_R(EIGTYPE, MKLTYPE, MKLFUNC) \ +template \ +struct general_matrix_matrix_rankupdate { \ + enum { \ + IsLower = (UpLo&Lower) == Lower, \ + LowUp = IsLower ? Lower : Upper, \ + conjA = ((AStorageOrder==ColMajor) && ConjugateA) ? 1 : 0 \ + }; \ + static EIGEN_STRONG_INLINE void run(Index size, Index depth,const EIGTYPE* lhs, Index lhsStride, \ + const EIGTYPE* rhs, Index rhsStride, EIGTYPE* res, Index resStride, EIGTYPE alpha) \ + { \ + /* typedef Matrix MatrixRhs;*/ \ +\ + MKL_INT lda=lhsStride, ldc=resStride, n=size, k=depth; \ + char uplo=(IsLower) ? 'L' : 'U', trans=(AStorageOrder==RowMajor) ? 'T':'N'; \ + MKLTYPE alpha_, beta_; \ +\ +/* Set alpha_ & beta_ */ \ + assign_scalar_eig2mkl(alpha_, alpha); \ + assign_scalar_eig2mkl(beta_, EIGTYPE(1)); \ + MKLFUNC(&uplo, &trans, &n, &k, &alpha_, lhs, &lda, &beta_, res, &ldc); \ + } \ +}; + +// HERK for complex data +#define EIGEN_MKL_RANKUPDATE_C(EIGTYPE, MKLTYPE, RTYPE, MKLFUNC) \ +template \ +struct general_matrix_matrix_rankupdate { \ + enum { \ + IsLower = (UpLo&Lower) == Lower, \ + LowUp = IsLower ? Lower : Upper, \ + conjA = (((AStorageOrder==ColMajor) && ConjugateA) || ((AStorageOrder==RowMajor) && !ConjugateA)) ? 1 : 0 \ + }; \ + static EIGEN_STRONG_INLINE void run(Index size, Index depth,const EIGTYPE* lhs, Index lhsStride, \ + const EIGTYPE* rhs, Index rhsStride, EIGTYPE* res, Index resStride, EIGTYPE alpha) \ + { \ + typedef Matrix MatrixType; \ +\ + MKL_INT lda=lhsStride, ldc=resStride, n=size, k=depth; \ + char uplo=(IsLower) ? 'L' : 'U', trans=(AStorageOrder==RowMajor) ? 'C':'N'; \ + RTYPE alpha_, beta_; \ + const EIGTYPE* a_ptr; \ +\ +/* Set alpha_ & beta_ */ \ +/* assign_scalar_eig2mkl(alpha_, alpha); */\ +/* assign_scalar_eig2mkl(beta_, EIGTYPE(1));*/ \ + alpha_ = alpha.real(); \ + beta_ = 1.0; \ +/* Copy with conjugation in some cases*/ \ + MatrixType a; \ + if (conjA) { \ + Map > mapA(lhs,n,k,OuterStride<>(lhsStride)); \ + a = mapA.conjugate(); \ + lda = a.outerStride(); \ + a_ptr = a.data(); \ + } else a_ptr=lhs; \ + MKLFUNC(&uplo, &trans, &n, &k, &alpha_, (MKLTYPE*)a_ptr, &lda, &beta_, (MKLTYPE*)res, &ldc); \ + } \ +}; + + +EIGEN_MKL_RANKUPDATE_R(double, double, dsyrk) +EIGEN_MKL_RANKUPDATE_R(float, float, ssyrk) + +//EIGEN_MKL_RANKUPDATE_C(dcomplex, MKL_Complex16, double, zherk) +//EIGEN_MKL_RANKUPDATE_C(scomplex, MKL_Complex8, double, cherk) + + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_MKL_H diff --git a/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h b/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h new file mode 100644 index 00000000000..060af328ebe --- /dev/null +++ b/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h @@ -0,0 +1,118 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * General matrix-matrix product functionality based on ?GEMM. + ******************************************************************************** +*/ + +#ifndef EIGEN_GENERAL_MATRIX_MATRIX_MKL_H +#define EIGEN_GENERAL_MATRIX_MATRIX_MKL_H + +namespace Eigen { + +namespace internal { + +/********************************************************************** +* This file implements general matrix-matrix multiplication using BLAS +* gemm function via partial specialization of +* general_matrix_matrix_product::run(..) method for float, double, +* std::complex and std::complex types +**********************************************************************/ + +// gemm specialization + +#define GEMM_SPECIALIZATION(EIGTYPE, EIGPREFIX, MKLTYPE, MKLPREFIX) \ +template< \ + typename Index, \ + int LhsStorageOrder, bool ConjugateLhs, \ + int RhsStorageOrder, bool ConjugateRhs> \ +struct general_matrix_matrix_product \ +{ \ +static void run(Index rows, Index cols, Index depth, \ + const EIGTYPE* _lhs, Index lhsStride, \ + const EIGTYPE* _rhs, Index rhsStride, \ + EIGTYPE* res, Index resStride, \ + EIGTYPE alpha, \ + level3_blocking& /*blocking*/, \ + GemmParallelInfo* /*info = 0*/) \ +{ \ + using std::conj; \ +\ + char transa, transb; \ + MKL_INT m, n, k, lda, ldb, ldc; \ + const EIGTYPE *a, *b; \ + MKLTYPE alpha_, beta_; \ + MatrixX##EIGPREFIX a_tmp, b_tmp; \ + EIGTYPE myone(1);\ +\ +/* Set transpose options */ \ + transa = (LhsStorageOrder==RowMajor) ? ((ConjugateLhs) ? 'C' : 'T') : 'N'; \ + transb = (RhsStorageOrder==RowMajor) ? ((ConjugateRhs) ? 'C' : 'T') : 'N'; \ +\ +/* Set m, n, k */ \ + m = (MKL_INT)rows; \ + n = (MKL_INT)cols; \ + k = (MKL_INT)depth; \ +\ +/* Set alpha_ & beta_ */ \ + assign_scalar_eig2mkl(alpha_, alpha); \ + assign_scalar_eig2mkl(beta_, myone); \ +\ +/* Set lda, ldb, ldc */ \ + lda = (MKL_INT)lhsStride; \ + ldb = (MKL_INT)rhsStride; \ + ldc = (MKL_INT)resStride; \ +\ +/* Set a, b, c */ \ + if ((LhsStorageOrder==ColMajor) && (ConjugateLhs)) { \ + Map > lhs(_lhs,m,k,OuterStride<>(lhsStride)); \ + a_tmp = lhs.conjugate(); \ + a = a_tmp.data(); \ + lda = a_tmp.outerStride(); \ + } else a = _lhs; \ +\ + if ((RhsStorageOrder==ColMajor) && (ConjugateRhs)) { \ + Map > rhs(_rhs,k,n,OuterStride<>(rhsStride)); \ + b_tmp = rhs.conjugate(); \ + b = b_tmp.data(); \ + ldb = b_tmp.outerStride(); \ + } else b = _rhs; \ +\ + MKLPREFIX##gemm(&transa, &transb, &m, &n, &k, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)b, &ldb, &beta_, (MKLTYPE*)res, &ldc); \ +}}; + +GEMM_SPECIALIZATION(double, d, double, d) +GEMM_SPECIALIZATION(float, f, float, s) +GEMM_SPECIALIZATION(dcomplex, cd, MKL_Complex16, z) +GEMM_SPECIALIZATION(scomplex, cf, MKL_Complex8, c) + +} // end namespase internal + +} // end namespace Eigen + +#endif // EIGEN_GENERAL_MATRIX_MATRIX_MKL_H diff --git a/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixVector.h b/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixVector.h index e0e2cbf8f62..ba1f73957db 100644 --- a/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixVector.h +++ b/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixVector.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008-2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_GENERAL_MATRIX_VECTOR_H #define EIGEN_GENERAL_MATRIX_VECTOR_H +namespace Eigen { + namespace internal { /* Optimized col-major matrix * vector product: @@ -40,8 +27,8 @@ namespace internal { * |cplx |real |cplx | invalid, the caller has to do tmp: = A * B; C += alpha*tmp * |cplx |real |real | optimal case, vectorization possible via real-cplx mul */ -template -struct general_matrix_vector_product +template +struct general_matrix_vector_product { typedef typename scalar_product_traits::ReturnType ResScalar; @@ -99,7 +86,7 @@ EIGEN_DONT_INLINE static void run( // How many coeffs of the result do we have to skip to be aligned. // Here we assume data are at least aligned on the base scalar type. - Index alignedStart = first_aligned(res,size); + Index alignedStart = internal::first_aligned(res,size); Index alignedSize = ResPacketSize>1 ? alignedStart + ((size-alignedStart) & ~ResPacketAlignedMask) : 0; const Index peeledSize = peels>1 ? alignedStart + ((alignedSize-alignedStart) & ~PeelAlignedMask) : alignedStart; @@ -109,7 +96,7 @@ EIGEN_DONT_INLINE static void run( : FirstAligned; // we cannot assume the first element is aligned because of sub-matrices - const Index lhsAlignmentOffset = first_aligned(lhs,size); + const Index lhsAlignmentOffset = internal::first_aligned(lhs,size); // find how many columns do we have to skip to be aligned with the result (if possible) Index skipColumns = 0; @@ -296,8 +283,8 @@ EIGEN_DONT_INLINE static void run( * - alpha is always a complex (or converted to a complex) * - no vectorization */ -template -struct general_matrix_vector_product +template +struct general_matrix_vector_product { typedef typename scalar_product_traits::ReturnType ResScalar; @@ -351,7 +338,7 @@ EIGEN_DONT_INLINE static void run( // How many coeffs of the result do we have to skip to be aligned. // Here we assume data are at least aligned on the base scalar type // if that's not the case then vectorization is discarded, see below. - Index alignedStart = first_aligned(rhs, depth); + Index alignedStart = internal::first_aligned(rhs, depth); Index alignedSize = RhsPacketSize>1 ? alignedStart + ((depth-alignedStart) & ~RhsPacketAlignedMask) : 0; const Index peeledSize = peels>1 ? alignedStart + ((alignedSize-alignedStart) & ~PeelAlignedMask) : alignedStart; @@ -361,7 +348,7 @@ EIGEN_DONT_INLINE static void run( : FirstAligned; // we cannot assume the first element is aligned because of sub-matrices - const Index lhsAlignmentOffset = first_aligned(lhs,depth); + const Index lhsAlignmentOffset = internal::first_aligned(lhs,depth); // find how many rows do we have to skip to be aligned with rhs (if possible) Index skipRows = 0; @@ -556,4 +543,6 @@ EIGEN_DONT_INLINE static void run( } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_GENERAL_MATRIX_VECTOR_H diff --git a/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixVector_MKL.h b/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixVector_MKL.h new file mode 100644 index 00000000000..e9de6af3ed1 --- /dev/null +++ b/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixVector_MKL.h @@ -0,0 +1,131 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * General matrix-vector product functionality based on ?GEMV. + ******************************************************************************** +*/ + +#ifndef EIGEN_GENERAL_MATRIX_VECTOR_MKL_H +#define EIGEN_GENERAL_MATRIX_VECTOR_MKL_H + +namespace Eigen { + +namespace internal { + +/********************************************************************** +* This file implements general matrix-vector multiplication using BLAS +* gemv function via partial specialization of +* general_matrix_vector_product::run(..) method for float, double, +* std::complex and std::complex types +**********************************************************************/ + +// gemv specialization + +template +struct general_matrix_vector_product_gemv : + general_matrix_vector_product {}; + +#define EIGEN_MKL_GEMV_SPECIALIZE(Scalar) \ +template \ +struct general_matrix_vector_product { \ +static EIGEN_DONT_INLINE void run( \ + Index rows, Index cols, \ + const Scalar* lhs, Index lhsStride, \ + const Scalar* rhs, Index rhsIncr, \ + Scalar* res, Index resIncr, Scalar alpha) \ +{ \ + if (ConjugateLhs) { \ + general_matrix_vector_product::run( \ + rows, cols, lhs, lhsStride, rhs, rhsIncr, res, resIncr, alpha); \ + } else { \ + general_matrix_vector_product_gemv::run( \ + rows, cols, lhs, lhsStride, rhs, rhsIncr, res, resIncr, alpha); \ + } \ +} \ +}; \ +template \ +struct general_matrix_vector_product { \ +static EIGEN_DONT_INLINE void run( \ + Index rows, Index cols, \ + const Scalar* lhs, Index lhsStride, \ + const Scalar* rhs, Index rhsIncr, \ + Scalar* res, Index resIncr, Scalar alpha) \ +{ \ + general_matrix_vector_product_gemv::run( \ + rows, cols, lhs, lhsStride, rhs, rhsIncr, res, resIncr, alpha); \ +} \ +}; \ + +EIGEN_MKL_GEMV_SPECIALIZE(double) +EIGEN_MKL_GEMV_SPECIALIZE(float) +EIGEN_MKL_GEMV_SPECIALIZE(dcomplex) +EIGEN_MKL_GEMV_SPECIALIZE(scomplex) + +#define EIGEN_MKL_GEMV_SPECIALIZATION(EIGTYPE,MKLTYPE,MKLPREFIX) \ +template \ +struct general_matrix_vector_product_gemv \ +{ \ +typedef Matrix GEMVVector;\ +\ +static EIGEN_DONT_INLINE void run( \ + Index rows, Index cols, \ + const EIGTYPE* lhs, Index lhsStride, \ + const EIGTYPE* rhs, Index rhsIncr, \ + EIGTYPE* res, Index resIncr, EIGTYPE alpha) \ +{ \ + MKL_INT m=rows, n=cols, lda=lhsStride, incx=rhsIncr, incy=resIncr; \ + MKLTYPE alpha_, beta_; \ + const EIGTYPE *x_ptr, myone(1); \ + char trans=(LhsStorageOrder==ColMajor) ? 'N' : (ConjugateLhs) ? 'C' : 'T'; \ + if (LhsStorageOrder==RowMajor) { \ + m=cols; \ + n=rows; \ + }\ + assign_scalar_eig2mkl(alpha_, alpha); \ + assign_scalar_eig2mkl(beta_, myone); \ + GEMVVector x_tmp; \ + if (ConjugateRhs) { \ + Map > map_x(rhs,cols,1,InnerStride<>(incx)); \ + x_tmp=map_x.conjugate(); \ + x_ptr=x_tmp.data(); \ + incx=1; \ + } else x_ptr=rhs; \ + MKLPREFIX##gemv(&trans, &m, &n, &alpha_, (const MKLTYPE*)lhs, &lda, (const MKLTYPE*)x_ptr, &incx, &beta_, (MKLTYPE*)res, &incy); \ +}\ +}; + +EIGEN_MKL_GEMV_SPECIALIZATION(double, double, d) +EIGEN_MKL_GEMV_SPECIALIZATION(float, float, s) +EIGEN_MKL_GEMV_SPECIALIZATION(dcomplex, MKL_Complex16, z) +EIGEN_MKL_GEMV_SPECIALIZATION(scomplex, MKL_Complex8, c) + +} // end namespase internal + +} // end namespace Eigen + +#endif // EIGEN_GENERAL_MATRIX_VECTOR_MKL_H diff --git a/extern/Eigen3/Eigen/src/Core/products/Parallelizer.h b/extern/Eigen3/Eigen/src/Core/products/Parallelizer.h index ecdedc363ce..5c3e9b7ac15 100644 --- a/extern/Eigen3/Eigen/src/Core/products/Parallelizer.h +++ b/extern/Eigen3/Eigen/src/Core/products/Parallelizer.h @@ -3,28 +3,15 @@ // // Copyright (C) 2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_PARALLELIZER_H #define EIGEN_PARALLELIZER_H +namespace Eigen { + namespace internal { /** \internal */ @@ -55,12 +42,23 @@ inline void manage_multi_threading(Action action, int* v) } } +} + +/** Must be call first when calling Eigen from multiple threads */ +inline void initParallel() +{ + int nbt; + internal::manage_multi_threading(GetAction, &nbt); + std::ptrdiff_t l1, l2; + internal::manage_caching_sizes(GetAction, &l1, &l2); +} + /** \returns the max number of threads reserved for Eigen * \sa setNbThreads */ inline int nbThreads() { int ret; - manage_multi_threading(GetAction, &ret); + internal::manage_multi_threading(GetAction, &ret); return ret; } @@ -68,9 +66,11 @@ inline int nbThreads() * \sa nbThreads */ inline void setNbThreads(int v) { - manage_multi_threading(SetAction, &v); + internal::manage_multi_threading(SetAction, &v); } +namespace internal { + template struct GemmParallelInfo { GemmParallelInfo() : sync(-1), users(0), rhs_start(0), rhs_length(0) {} @@ -85,7 +85,9 @@ template struct GemmParallelInfo template void parallelize_gemm(const Functor& func, Index rows, Index cols, bool transpose) { -#ifndef EIGEN_HAS_OPENMP + // TODO when EIGEN_USE_BLAS is defined, + // we should still enable OMP for other scalar types +#if !(defined (EIGEN_HAS_OPENMP)) || defined (EIGEN_USE_BLAS) // FIXME the transpose variable is only needed to properly split // the matrix product when multithreading is enabled. This is a temporary // fix to support row-major destination matrices. This whole @@ -117,6 +119,7 @@ void parallelize_gemm(const Functor& func, Index rows, Index cols, bool transpos if(threads==1) return func(0,rows, 0,cols); + Eigen::initParallel(); func.initParallelSession(); if(transpose) @@ -151,4 +154,6 @@ void parallelize_gemm(const Functor& func, Index rows, Index cols, bool transpos } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_PARALLELIZER_H diff --git a/extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix.h b/extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix.h index ccd757cfaf8..48209636eed 100644 --- a/extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix.h +++ b/extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SELFADJOINT_MATRIX_MATRIX_H #define EIGEN_SELFADJOINT_MATRIX_MATRIX_H +namespace Eigen { + namespace internal { // pack a selfadjoint block diagonal for use with the gebp_kernel @@ -400,8 +387,8 @@ struct SelfadjointProductMatrix { eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); - const ActualLhsType lhs = LhsBlasTraits::extract(m_lhs); - const ActualRhsType rhs = RhsBlasTraits::extract(m_rhs); + typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(m_lhs); + typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(m_rhs); Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(m_lhs) * RhsBlasTraits::extractScalarFactor(m_rhs); @@ -424,4 +411,6 @@ struct SelfadjointProductMatrix } }; +} // end namespace Eigen + #endif // EIGEN_SELFADJOINT_MATRIX_MATRIX_H diff --git a/extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h b/extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h new file mode 100644 index 00000000000..4e5c4125c01 --- /dev/null +++ b/extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h @@ -0,0 +1,295 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * Self adjoint matrix * matrix product functionality based on ?SYMM/?HEMM. + ******************************************************************************** +*/ + +#ifndef EIGEN_SELFADJOINT_MATRIX_MATRIX_MKL_H +#define EIGEN_SELFADJOINT_MATRIX_MATRIX_MKL_H + +namespace Eigen { + +namespace internal { + + +/* Optimized selfadjoint matrix * matrix (?SYMM/?HEMM) product */ + +#define EIGEN_MKL_SYMM_L(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \ +template \ +struct product_selfadjoint_matrix \ +{\ +\ + static EIGEN_DONT_INLINE void run( \ + Index rows, Index cols, \ + const EIGTYPE* _lhs, Index lhsStride, \ + const EIGTYPE* _rhs, Index rhsStride, \ + EIGTYPE* res, Index resStride, \ + EIGTYPE alpha) \ + { \ + char side='L', uplo='L'; \ + MKL_INT m, n, lda, ldb, ldc; \ + const EIGTYPE *a, *b; \ + MKLTYPE alpha_, beta_; \ + MatrixX##EIGPREFIX b_tmp; \ + EIGTYPE myone(1);\ +\ +/* Set transpose options */ \ +/* Set m, n, k */ \ + m = (MKL_INT)rows; \ + n = (MKL_INT)cols; \ +\ +/* Set alpha_ & beta_ */ \ + assign_scalar_eig2mkl(alpha_, alpha); \ + assign_scalar_eig2mkl(beta_, myone); \ +\ +/* Set lda, ldb, ldc */ \ + lda = (MKL_INT)lhsStride; \ + ldb = (MKL_INT)rhsStride; \ + ldc = (MKL_INT)resStride; \ +\ +/* Set a, b, c */ \ + if (LhsStorageOrder==RowMajor) uplo='U'; \ + a = _lhs; \ +\ + if (RhsStorageOrder==RowMajor) { \ + Map > rhs(_rhs,n,m,OuterStride<>(rhsStride)); \ + b_tmp = rhs.adjoint(); \ + b = b_tmp.data(); \ + ldb = b_tmp.outerStride(); \ + } else b = _rhs; \ +\ + MKLPREFIX##symm(&side, &uplo, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)b, &ldb, &beta_, (MKLTYPE*)res, &ldc); \ +\ + } \ +}; + + +#define EIGEN_MKL_HEMM_L(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \ +template \ +struct product_selfadjoint_matrix \ +{\ + static EIGEN_DONT_INLINE void run( \ + Index rows, Index cols, \ + const EIGTYPE* _lhs, Index lhsStride, \ + const EIGTYPE* _rhs, Index rhsStride, \ + EIGTYPE* res, Index resStride, \ + EIGTYPE alpha) \ + { \ + char side='L', uplo='L'; \ + MKL_INT m, n, lda, ldb, ldc; \ + const EIGTYPE *a, *b; \ + MKLTYPE alpha_, beta_; \ + MatrixX##EIGPREFIX b_tmp; \ + Matrix a_tmp; \ + EIGTYPE myone(1); \ +\ +/* Set transpose options */ \ +/* Set m, n, k */ \ + m = (MKL_INT)rows; \ + n = (MKL_INT)cols; \ +\ +/* Set alpha_ & beta_ */ \ + assign_scalar_eig2mkl(alpha_, alpha); \ + assign_scalar_eig2mkl(beta_, myone); \ +\ +/* Set lda, ldb, ldc */ \ + lda = (MKL_INT)lhsStride; \ + ldb = (MKL_INT)rhsStride; \ + ldc = (MKL_INT)resStride; \ +\ +/* Set a, b, c */ \ + if (((LhsStorageOrder==ColMajor) && ConjugateLhs) || ((LhsStorageOrder==RowMajor) && (!ConjugateLhs))) { \ + Map, 0, OuterStride<> > lhs(_lhs,m,m,OuterStride<>(lhsStride)); \ + a_tmp = lhs.conjugate(); \ + a = a_tmp.data(); \ + lda = a_tmp.outerStride(); \ + } else a = _lhs; \ + if (LhsStorageOrder==RowMajor) uplo='U'; \ +\ + if (RhsStorageOrder==ColMajor && (!ConjugateRhs)) { \ + b = _rhs; } \ + else { \ + if (RhsStorageOrder==ColMajor && ConjugateRhs) { \ + Map > rhs(_rhs,m,n,OuterStride<>(rhsStride)); \ + b_tmp = rhs.conjugate(); \ + } else \ + if (ConjugateRhs) { \ + Map > rhs(_rhs,n,m,OuterStride<>(rhsStride)); \ + b_tmp = rhs.adjoint(); \ + } else { \ + Map > rhs(_rhs,n,m,OuterStride<>(rhsStride)); \ + b_tmp = rhs.transpose(); \ + } \ + b = b_tmp.data(); \ + ldb = b_tmp.outerStride(); \ + } \ +\ + MKLPREFIX##hemm(&side, &uplo, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)b, &ldb, &beta_, (MKLTYPE*)res, &ldc); \ +\ + } \ +}; + +EIGEN_MKL_SYMM_L(double, double, d, d) +EIGEN_MKL_SYMM_L(float, float, f, s) +EIGEN_MKL_HEMM_L(dcomplex, MKL_Complex16, cd, z) +EIGEN_MKL_HEMM_L(scomplex, MKL_Complex8, cf, c) + + +/* Optimized matrix * selfadjoint matrix (?SYMM/?HEMM) product */ + +#define EIGEN_MKL_SYMM_R(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \ +template \ +struct product_selfadjoint_matrix \ +{\ +\ + static EIGEN_DONT_INLINE void run( \ + Index rows, Index cols, \ + const EIGTYPE* _lhs, Index lhsStride, \ + const EIGTYPE* _rhs, Index rhsStride, \ + EIGTYPE* res, Index resStride, \ + EIGTYPE alpha) \ + { \ + char side='R', uplo='L'; \ + MKL_INT m, n, lda, ldb, ldc; \ + const EIGTYPE *a, *b; \ + MKLTYPE alpha_, beta_; \ + MatrixX##EIGPREFIX b_tmp; \ + EIGTYPE myone(1);\ +\ +/* Set m, n, k */ \ + m = (MKL_INT)rows; \ + n = (MKL_INT)cols; \ +\ +/* Set alpha_ & beta_ */ \ + assign_scalar_eig2mkl(alpha_, alpha); \ + assign_scalar_eig2mkl(beta_, myone); \ +\ +/* Set lda, ldb, ldc */ \ + lda = (MKL_INT)rhsStride; \ + ldb = (MKL_INT)lhsStride; \ + ldc = (MKL_INT)resStride; \ +\ +/* Set a, b, c */ \ + if (RhsStorageOrder==RowMajor) uplo='U'; \ + a = _rhs; \ +\ + if (LhsStorageOrder==RowMajor) { \ + Map > lhs(_lhs,n,m,OuterStride<>(rhsStride)); \ + b_tmp = lhs.adjoint(); \ + b = b_tmp.data(); \ + ldb = b_tmp.outerStride(); \ + } else b = _lhs; \ +\ + MKLPREFIX##symm(&side, &uplo, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)b, &ldb, &beta_, (MKLTYPE*)res, &ldc); \ +\ + } \ +}; + + +#define EIGEN_MKL_HEMM_R(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \ +template \ +struct product_selfadjoint_matrix \ +{\ + static EIGEN_DONT_INLINE void run( \ + Index rows, Index cols, \ + const EIGTYPE* _lhs, Index lhsStride, \ + const EIGTYPE* _rhs, Index rhsStride, \ + EIGTYPE* res, Index resStride, \ + EIGTYPE alpha) \ + { \ + char side='R', uplo='L'; \ + MKL_INT m, n, lda, ldb, ldc; \ + const EIGTYPE *a, *b; \ + MKLTYPE alpha_, beta_; \ + MatrixX##EIGPREFIX b_tmp; \ + Matrix a_tmp; \ + EIGTYPE myone(1); \ +\ +/* Set m, n, k */ \ + m = (MKL_INT)rows; \ + n = (MKL_INT)cols; \ +\ +/* Set alpha_ & beta_ */ \ + assign_scalar_eig2mkl(alpha_, alpha); \ + assign_scalar_eig2mkl(beta_, myone); \ +\ +/* Set lda, ldb, ldc */ \ + lda = (MKL_INT)rhsStride; \ + ldb = (MKL_INT)lhsStride; \ + ldc = (MKL_INT)resStride; \ +\ +/* Set a, b, c */ \ + if (((RhsStorageOrder==ColMajor) && ConjugateRhs) || ((RhsStorageOrder==RowMajor) && (!ConjugateRhs))) { \ + Map, 0, OuterStride<> > rhs(_rhs,n,n,OuterStride<>(rhsStride)); \ + a_tmp = rhs.conjugate(); \ + a = a_tmp.data(); \ + lda = a_tmp.outerStride(); \ + } else a = _rhs; \ + if (RhsStorageOrder==RowMajor) uplo='U'; \ +\ + if (LhsStorageOrder==ColMajor && (!ConjugateLhs)) { \ + b = _lhs; } \ + else { \ + if (LhsStorageOrder==ColMajor && ConjugateLhs) { \ + Map > lhs(_lhs,m,n,OuterStride<>(lhsStride)); \ + b_tmp = lhs.conjugate(); \ + } else \ + if (ConjugateLhs) { \ + Map > lhs(_lhs,n,m,OuterStride<>(lhsStride)); \ + b_tmp = lhs.adjoint(); \ + } else { \ + Map > lhs(_lhs,n,m,OuterStride<>(lhsStride)); \ + b_tmp = lhs.transpose(); \ + } \ + b = b_tmp.data(); \ + ldb = b_tmp.outerStride(); \ + } \ +\ + MKLPREFIX##hemm(&side, &uplo, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (const MKLTYPE*)b, &ldb, &beta_, (MKLTYPE*)res, &ldc); \ + } \ +}; + +EIGEN_MKL_SYMM_R(double, double, d, d) +EIGEN_MKL_SYMM_R(float, float, f, s) +EIGEN_MKL_HEMM_R(dcomplex, MKL_Complex16, cd, z) +EIGEN_MKL_HEMM_R(scomplex, MKL_Complex8, cf, c) + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_SELFADJOINT_MATRIX_MATRIX_MKL_H diff --git a/extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixVector.h b/extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixVector.h index d6121fc07bd..c3145c69a5f 100644 --- a/extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixVector.h +++ b/extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixVector.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008-2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SELFADJOINT_MATRIX_VECTOR_H #define EIGEN_SELFADJOINT_MATRIX_VECTOR_H +namespace Eigen { + namespace internal { /* Optimized selfadjoint matrix * vector product: @@ -32,8 +19,15 @@ namespace internal { * the number of load/stores of the result by a factor 2 and to reduce * the instruction dependency. */ -template -static EIGEN_DONT_INLINE void product_selfadjoint_vector( + +template +struct selfadjoint_matrix_vector_product; + +template +struct selfadjoint_matrix_vector_product + +{ +static EIGEN_DONT_INLINE void run( Index size, const Scalar* lhs, Index lhsStride, const Scalar* _rhs, Index rhsIncr, @@ -85,14 +79,14 @@ static EIGEN_DONT_INLINE void product_selfadjoint_vector( Scalar t1 = cjAlpha * rhs[j+1]; Packet ptmp1 = pset1(t1); - Scalar t2 = 0; + Scalar t2(0); Packet ptmp2 = pset1(t2); - Scalar t3 = 0; + Scalar t3(0); Packet ptmp3 = pset1(t3); size_t starti = FirstTriangular ? 0 : j+2; size_t endi = FirstTriangular ? j : size; - size_t alignedStart = (starti) + first_aligned(&res[starti], endi-starti); + size_t alignedStart = (starti) + internal::first_aligned(&res[starti], endi-starti); size_t alignedEnd = alignedStart + ((endi-alignedStart)/(PacketSize))*(PacketSize); // TODO make sure this product is a real * complex and that the rhs is properly conjugated if needed @@ -148,7 +142,7 @@ static EIGEN_DONT_INLINE void product_selfadjoint_vector( register const Scalar* EIGEN_RESTRICT A0 = lhs + j*lhsStride; Scalar t1 = cjAlpha * rhs[j]; - Scalar t2 = 0; + Scalar t2(0); // TODO make sure this product is a real * complex and that the rhs is properly conjugated if needed res[j] += cjd.pmul(internal::real(A0[j]), t1); for (Index i=FirstTriangular ? 0 : j+1; i<(FirstTriangular ? j : size); i++) @@ -159,6 +153,7 @@ static EIGEN_DONT_INLINE void product_selfadjoint_vector( res[j] += alpha * t2; } } +}; } // end namespace internal @@ -193,8 +188,8 @@ struct SelfadjointProductMatrix eigen_assert(dest.rows()==m_lhs.rows() && dest.cols()==m_rhs.cols()); - const ActualLhsType lhs = LhsBlasTraits::extract(m_lhs); - const ActualRhsType rhs = RhsBlasTraits::extract(m_rhs); + typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(m_lhs); + typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(m_rhs); Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(m_lhs) * RhsBlasTraits::extractScalarFactor(m_rhs); @@ -232,7 +227,7 @@ struct SelfadjointProductMatrix } - internal::product_selfadjoint_vector::Flags&RowMajorBit) ? RowMajor : ColMajor, int(LhsUpLo), bool(LhsBlasTraits::NeedToConjugate), bool(RhsBlasTraits::NeedToConjugate)> + internal::selfadjoint_matrix_vector_product::Flags&RowMajorBit) ? RowMajor : ColMajor, int(LhsUpLo), bool(LhsBlasTraits::NeedToConjugate), bool(RhsBlasTraits::NeedToConjugate)>::run ( lhs.rows(), // size &lhs.coeffRef(0,0), lhs.outerStride(), // lhs info @@ -274,5 +269,6 @@ struct SelfadjointProductMatrix } }; +} // end namespace Eigen #endif // EIGEN_SELFADJOINT_MATRIX_VECTOR_H diff --git a/extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h b/extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h new file mode 100644 index 00000000000..f88d483b653 --- /dev/null +++ b/extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h @@ -0,0 +1,114 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * Selfadjoint matrix-vector product functionality based on ?SYMV/HEMV. + ******************************************************************************** +*/ + +#ifndef EIGEN_SELFADJOINT_MATRIX_VECTOR_MKL_H +#define EIGEN_SELFADJOINT_MATRIX_VECTOR_MKL_H + +namespace Eigen { + +namespace internal { + +/********************************************************************** +* This file implements selfadjoint matrix-vector multiplication using BLAS +**********************************************************************/ + +// symv/hemv specialization + +template +struct selfadjoint_matrix_vector_product_symv : + selfadjoint_matrix_vector_product {}; + +#define EIGEN_MKL_SYMV_SPECIALIZE(Scalar) \ +template \ +struct selfadjoint_matrix_vector_product { \ +static EIGEN_DONT_INLINE void run( \ + Index size, const Scalar* lhs, Index lhsStride, \ + const Scalar* _rhs, Index rhsIncr, Scalar* res, Scalar alpha) { \ + enum {\ + IsColMajor = StorageOrder==ColMajor \ + }; \ + if (IsColMajor == ConjugateLhs) {\ + selfadjoint_matrix_vector_product::run( \ + size, lhs, lhsStride, _rhs, rhsIncr, res, alpha); \ + } else {\ + selfadjoint_matrix_vector_product_symv::run( \ + size, lhs, lhsStride, _rhs, rhsIncr, res, alpha); \ + }\ + } \ +}; \ + +EIGEN_MKL_SYMV_SPECIALIZE(double) +EIGEN_MKL_SYMV_SPECIALIZE(float) +EIGEN_MKL_SYMV_SPECIALIZE(dcomplex) +EIGEN_MKL_SYMV_SPECIALIZE(scomplex) + +#define EIGEN_MKL_SYMV_SPECIALIZATION(EIGTYPE,MKLTYPE,MKLFUNC) \ +template \ +struct selfadjoint_matrix_vector_product_symv \ +{ \ +typedef Matrix SYMVVector;\ +\ +static EIGEN_DONT_INLINE void run( \ +Index size, const EIGTYPE* lhs, Index lhsStride, \ +const EIGTYPE* _rhs, Index rhsIncr, EIGTYPE* res, EIGTYPE alpha) \ +{ \ + enum {\ + IsRowMajor = StorageOrder==RowMajor ? 1 : 0, \ + IsLower = UpLo == Lower ? 1 : 0 \ + }; \ + MKL_INT n=size, lda=lhsStride, incx=rhsIncr, incy=1; \ + MKLTYPE alpha_, beta_; \ + const EIGTYPE *x_ptr, myone(1); \ + char uplo=(IsRowMajor) ? (IsLower ? 'U' : 'L') : (IsLower ? 'L' : 'U'); \ + assign_scalar_eig2mkl(alpha_, alpha); \ + assign_scalar_eig2mkl(beta_, myone); \ + SYMVVector x_tmp; \ + if (ConjugateRhs) { \ + Map > map_x(_rhs,size,1,InnerStride<>(incx)); \ + x_tmp=map_x.conjugate(); \ + x_ptr=x_tmp.data(); \ + incx=1; \ + } else x_ptr=_rhs; \ + MKLFUNC(&uplo, &n, &alpha_, (const MKLTYPE*)lhs, &lda, (const MKLTYPE*)x_ptr, &incx, &beta_, (MKLTYPE*)res, &incy); \ +}\ +}; + +EIGEN_MKL_SYMV_SPECIALIZATION(double, double, dsymv) +EIGEN_MKL_SYMV_SPECIALIZATION(float, float, ssymv) +EIGEN_MKL_SYMV_SPECIALIZATION(dcomplex, MKL_Complex16, zhemv) +EIGEN_MKL_SYMV_SPECIALIZATION(scomplex, MKL_Complex8, chemv) + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_SELFADJOINT_MATRIX_VECTOR_MKL_H diff --git a/extern/Eigen3/Eigen/src/Core/products/SelfadjointProduct.h b/extern/Eigen3/Eigen/src/Core/products/SelfadjointProduct.h index 3a4523fa4a9..6a55f3d7715 100644 --- a/extern/Eigen3/Eigen/src/Core/products/SelfadjointProduct.h +++ b/extern/Eigen3/Eigen/src/Core/products/SelfadjointProduct.h @@ -3,24 +3,9 @@ // // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SELFADJOINT_PRODUCT_H #define EIGEN_SELFADJOINT_PRODUCT_H @@ -31,6 +16,8 @@ * It corresponds to the level 3 SYRK and level 2 SYR Blas routines. **********************************************************************/ +namespace Eigen { + template struct selfadjoint_rank1_update; @@ -72,7 +59,7 @@ struct selfadjoint_product_selector typedef internal::blas_traits OtherBlasTraits; typedef typename OtherBlasTraits::DirectLinearAccessType ActualOtherType; typedef typename internal::remove_all::type _ActualOtherType; - const ActualOtherType actualOther = OtherBlasTraits::extract(other.derived()); + typename internal::add_const_on_value_type::type actualOther = OtherBlasTraits::extract(other.derived()); Scalar actualAlpha = alpha * OtherBlasTraits::extractScalarFactor(other.derived()); @@ -105,12 +92,12 @@ struct selfadjoint_product_selector typedef internal::blas_traits OtherBlasTraits; typedef typename OtherBlasTraits::DirectLinearAccessType ActualOtherType; typedef typename internal::remove_all::type _ActualOtherType; - const ActualOtherType actualOther = OtherBlasTraits::extract(other.derived()); + typename internal::add_const_on_value_type::type actualOther = OtherBlasTraits::extract(other.derived()); Scalar actualAlpha = alpha * OtherBlasTraits::extractScalarFactor(other.derived()); enum { IsRowMajor = (internal::traits::Flags&RowMajorBit) ? 1 : 0 }; - + internal::general_matrix_matrix_triangular_product::IsComplex, Scalar, _ActualOtherType::Flags&RowMajorBit ? ColMajor : RowMajor, (!OtherBlasTraits::NeedToConjugate) && NumTraits::IsComplex, @@ -133,4 +120,6 @@ SelfAdjointView& SelfAdjointView return *this; } +} // end namespace Eigen + #endif // EIGEN_SELFADJOINT_PRODUCT_H diff --git a/extern/Eigen3/Eigen/src/Core/products/SelfadjointRank2Update.h b/extern/Eigen3/Eigen/src/Core/products/SelfadjointRank2Update.h index 9f8b8438a5d..57a98cc2de9 100644 --- a/extern/Eigen3/Eigen/src/Core/products/SelfadjointRank2Update.h +++ b/extern/Eigen3/Eigen/src/Core/products/SelfadjointRank2Update.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SELFADJOINTRANK2UPTADE_H #define EIGEN_SELFADJOINTRANK2UPTADE_H +namespace Eigen { + namespace internal { /* Optimized selfadjoint matrix += alpha * uv' + conj(alpha)*vu' @@ -76,12 +63,12 @@ SelfAdjointView& SelfAdjointView typedef internal::blas_traits UBlasTraits; typedef typename UBlasTraits::DirectLinearAccessType ActualUType; typedef typename internal::remove_all::type _ActualUType; - const ActualUType actualU = UBlasTraits::extract(u.derived()); + typename internal::add_const_on_value_type::type actualU = UBlasTraits::extract(u.derived()); typedef internal::blas_traits VBlasTraits; typedef typename VBlasTraits::DirectLinearAccessType ActualVType; typedef typename internal::remove_all::type _ActualVType; - const ActualVType actualV = VBlasTraits::extract(v.derived()); + typename internal::add_const_on_value_type::type actualV = VBlasTraits::extract(v.derived()); // If MatrixType is row major, then we use the routine for lower triangular in the upper triangular case and // vice versa, and take the complex conjugate of all coefficients and vector entries. @@ -101,4 +88,6 @@ SelfAdjointView& SelfAdjointView return *this; } +} // end namespace Eigen + #endif // EIGEN_SELFADJOINTRANK2UPTADE_H diff --git a/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix.h b/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix.h index 0c48d2efb75..92cba66f615 100644 --- a/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix.h +++ b/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_TRIANGULAR_MATRIX_MATRIX_H #define EIGEN_TRIANGULAR_MATRIX_MATRIX_H +namespace Eigen { + namespace internal { // template @@ -58,23 +45,23 @@ template + int ResStorageOrder, int Version = Specialized> struct product_triangular_matrix_matrix; template + int RhsStorageOrder, bool ConjugateRhs, int Version> struct product_triangular_matrix_matrix + RhsStorageOrder,ConjugateRhs,RowMajor,Version> { static EIGEN_STRONG_INLINE void run( Index rows, Index cols, Index depth, const Scalar* lhs, Index lhsStride, const Scalar* rhs, Index rhsStride, Scalar* res, Index resStride, - Scalar alpha) + Scalar alpha, level3_blocking& blocking) { product_triangular_matrix_matrix - ::run(cols, rows, depth, rhs, rhsStride, lhs, lhsStride, res, resStride, alpha); + ::run(cols, rows, depth, rhs, rhsStride, lhs, lhsStride, res, resStride, alpha, blocking); } }; // implements col-major += alpha * op(triangular) * op(general) template + int RhsStorageOrder, bool ConjugateRhs, int Version> struct product_triangular_matrix_matrix + RhsStorageOrder,ConjugateRhs,ColMajor,Version> { typedef gebp_traits Traits; enum { - SmallPanelWidth = EIGEN_PLAIN_ENUM_MAX(Traits::mr,Traits::nr), + SmallPanelWidth = 2 * EIGEN_PLAIN_ENUM_MAX(Traits::mr,Traits::nr), IsLower = (Mode&Lower) == Lower, SetDiag = (Mode&(ZeroDiag|UnitDiag)) ? 0 : 1 }; @@ -109,7 +96,7 @@ struct product_triangular_matrix_matrix& blocking) { // strip zeros Index diagSize = (std::min)(_rows,_depth); @@ -120,15 +107,16 @@ struct product_triangular_matrix_matrix lhs(_lhs,lhsStride); const_blas_data_mapper rhs(_rhs,rhsStride); - Index kc = depth; // cache block size along the K direction - Index mc = rows; // cache block size along the M direction - Index nc = cols; // cache block size along the N direction - computeProductBlockingSizes(kc, mc, nc); + Index kc = blocking.kc(); // cache block size along the K direction + Index mc = (std::min)(rows,blocking.mc()); // cache block size along the M direction + + std::size_t sizeA = kc*mc; + std::size_t sizeB = kc*cols; std::size_t sizeW = kc*Traits::WorkSpaceFactor; - std::size_t sizeB = sizeW + kc*cols; - ei_declare_aligned_stack_constructed_variable(Scalar, blockA, kc*mc, 0); - ei_declare_aligned_stack_constructed_variable(Scalar, allocatedBlockB, sizeB, 0); - Scalar* blockB = allocatedBlockB + sizeW; + + ei_declare_aligned_stack_constructed_variable(Scalar, blockA, sizeA, blocking.blockA()); + ei_declare_aligned_stack_constructed_variable(Scalar, blockB, sizeB, blocking.blockB()); + ei_declare_aligned_stack_constructed_variable(Scalar, blockW, sizeW, blocking.blockW()); Matrix triangularBuffer; triangularBuffer.setZero(); @@ -186,7 +174,7 @@ struct product_triangular_matrix_matrix0) @@ -196,7 +184,7 @@ struct product_triangular_matrix_matrix() (blockA, &lhs(i2, actual_k2), lhsStride, actual_kc, actual_mc); - gebp_kernel(res+i2, resStride, blockA, blockB, actual_mc, actual_kc, cols, alpha); + gebp_kernel(res+i2, resStride, blockA, blockB, actual_mc, actual_kc, cols, alpha, -1, -1, 0, 0, blockW); } } } @@ -220,10 +208,10 @@ struct product_triangular_matrix_matrix + int RhsStorageOrder, bool ConjugateRhs, int Version> struct product_triangular_matrix_matrix + RhsStorageOrder,ConjugateRhs,ColMajor,Version> { typedef gebp_traits Traits; enum { @@ -237,7 +225,7 @@ struct product_triangular_matrix_matrix& blocking) { // strip zeros Index diagSize = (std::min)(_cols,_depth); @@ -248,16 +236,16 @@ struct product_triangular_matrix_matrix lhs(_lhs,lhsStride); const_blas_data_mapper rhs(_rhs,rhsStride); - Index kc = depth; // cache block size along the K direction - Index mc = rows; // cache block size along the M direction - Index nc = cols; // cache block size along the N direction - computeProductBlockingSizes(kc, mc, nc); + Index kc = blocking.kc(); // cache block size along the K direction + Index mc = (std::min)(rows,blocking.mc()); // cache block size along the M direction + std::size_t sizeA = kc*mc; + std::size_t sizeB = kc*cols; std::size_t sizeW = kc*Traits::WorkSpaceFactor; - std::size_t sizeB = sizeW + kc*cols; - ei_declare_aligned_stack_constructed_variable(Scalar, blockA, kc*mc, 0); - ei_declare_aligned_stack_constructed_variable(Scalar, allocatedBlockB, sizeB, 0); - Scalar* blockB = allocatedBlockB + sizeW; + + ei_declare_aligned_stack_constructed_variable(Scalar, blockA, sizeA, blocking.blockA()); + ei_declare_aligned_stack_constructed_variable(Scalar, blockB, sizeB, blocking.blockB()); + ei_declare_aligned_stack_constructed_variable(Scalar, blockW, sizeW, blocking.blockW()); Matrix triangularBuffer; triangularBuffer.setZero(); @@ -345,13 +333,13 @@ struct product_triangular_matrix_matrix template void scaleAndAddTo(Dest& dst, Scalar alpha) const { - const ActualLhsType lhs = LhsBlasTraits::extract(m_lhs); - const ActualRhsType rhs = RhsBlasTraits::extract(m_rhs); + typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(m_lhs); + typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(m_rhs); Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(m_lhs) * RhsBlasTraits::extractScalarFactor(m_rhs); + typedef internal::gemm_blocking_space<(Dest::Flags&RowMajorBit) ? RowMajor : ColMajor,Scalar,Scalar, + Lhs::MaxRowsAtCompileTime, Rhs::MaxColsAtCompileTime, Lhs::MaxColsAtCompileTime,4> BlockingType; + + enum { IsLower = (Mode&Lower) == Lower }; + Index stripedRows = ((!LhsIsTriangular) || (IsLower)) ? lhs.rows() : (std::min)(lhs.rows(),lhs.cols()); + Index stripedCols = ((LhsIsTriangular) || (!IsLower)) ? rhs.cols() : (std::min)(rhs.cols(),rhs.rows()); + Index stripedDepth = LhsIsTriangular ? ((!IsLower) ? lhs.cols() : (std::min)(lhs.cols(),lhs.rows())) + : ((IsLower) ? rhs.rows() : (std::min)(rhs.rows(),rhs.cols())); + + BlockingType blocking(stripedRows, stripedCols, stripedDepth); + internal::product_triangular_matrix_matrix::Flags&RowMajorBit) ? RowMajor : ColMajor, LhsBlasTraits::NeedToConjugate, (internal::traits<_ActualRhsType>::Flags&RowMajorBit) ? RowMajor : ColMajor, RhsBlasTraits::NeedToConjugate, (internal::traits::Flags&RowMajorBit) ? RowMajor : ColMajor> ::run( - lhs.rows(), rhs.cols(), lhs.cols(),// LhsIsTriangular ? rhs.cols() : lhs.rows(), // sizes + stripedRows, stripedCols, stripedDepth, // sizes &lhs.coeffRef(0,0), lhs.outerStride(), // lhs info &rhs.coeffRef(0,0), rhs.outerStride(), // rhs info - &dst.coeffRef(0,0), dst.outerStride(), // result info - actualAlpha // alpha + &dst.coeffRef(0,0), dst.outerStride(), // result info + actualAlpha, blocking ); } }; +} // end namespace Eigen #endif // EIGEN_TRIANGULAR_MATRIX_MATRIX_H diff --git a/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h b/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h new file mode 100644 index 00000000000..8173da5bb6d --- /dev/null +++ b/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h @@ -0,0 +1,309 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * Triangular matrix * matrix product functionality based on ?TRMM. + ******************************************************************************** +*/ + +#ifndef EIGEN_TRIANGULAR_MATRIX_MATRIX_MKL_H +#define EIGEN_TRIANGULAR_MATRIX_MATRIX_MKL_H + +namespace Eigen { + +namespace internal { + + +template +struct product_triangular_matrix_matrix_trmm : + product_triangular_matrix_matrix {}; + + +// try to go to BLAS specialization +#define EIGEN_MKL_TRMM_SPECIALIZE(Scalar, LhsIsTriangular) \ +template \ +struct product_triangular_matrix_matrix { \ + static inline void run(Index _rows, Index _cols, Index _depth, const Scalar* _lhs, Index lhsStride,\ + const Scalar* _rhs, Index rhsStride, Scalar* res, Index resStride, Scalar alpha) { \ + product_triangular_matrix_matrix_trmm::run( \ + _rows, _cols, _depth, _lhs, lhsStride, _rhs, rhsStride, res, resStride, alpha); \ + } \ +}; + +EIGEN_MKL_TRMM_SPECIALIZE(double, true) +EIGEN_MKL_TRMM_SPECIALIZE(double, false) +EIGEN_MKL_TRMM_SPECIALIZE(dcomplex, true) +EIGEN_MKL_TRMM_SPECIALIZE(dcomplex, false) +EIGEN_MKL_TRMM_SPECIALIZE(float, true) +EIGEN_MKL_TRMM_SPECIALIZE(float, false) +EIGEN_MKL_TRMM_SPECIALIZE(scomplex, true) +EIGEN_MKL_TRMM_SPECIALIZE(scomplex, false) + +// implements col-major += alpha * op(triangular) * op(general) +#define EIGEN_MKL_TRMM_L(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \ +template \ +struct product_triangular_matrix_matrix_trmm \ +{ \ + enum { \ + IsLower = (Mode&Lower) == Lower, \ + SetDiag = (Mode&(ZeroDiag|UnitDiag)) ? 0 : 1, \ + IsUnitDiag = (Mode&UnitDiag) ? 1 : 0, \ + IsZeroDiag = (Mode&ZeroDiag) ? 1 : 0, \ + LowUp = IsLower ? Lower : Upper, \ + conjA = ((LhsStorageOrder==ColMajor) && ConjugateLhs) ? 1 : 0 \ + }; \ +\ + static EIGEN_DONT_INLINE void run( \ + Index _rows, Index _cols, Index _depth, \ + const EIGTYPE* _lhs, Index lhsStride, \ + const EIGTYPE* _rhs, Index rhsStride, \ + EIGTYPE* res, Index resStride, \ + EIGTYPE alpha) \ + { \ + Index diagSize = (std::min)(_rows,_depth); \ + Index rows = IsLower ? _rows : diagSize; \ + Index depth = IsLower ? diagSize : _depth; \ + Index cols = _cols; \ +\ + typedef Matrix MatrixLhs; \ + typedef Matrix MatrixRhs; \ +\ +/* Non-square case - doesn't fit to MKL ?TRMM. Fall to default triangular product or call MKL ?GEMM*/ \ + if (rows != depth) { \ +\ + int nthr = mkl_domain_get_max_threads(MKL_BLAS); \ +\ + if (((nthr==1) && (((std::max)(rows,depth)-diagSize)/(double)diagSize < 0.5))) { \ + /* Most likely no benefit to call TRMM or GEMM from MKL*/ \ + product_triangular_matrix_matrix::run( \ + _rows, _cols, _depth, _lhs, lhsStride, _rhs, rhsStride, res, resStride, alpha); \ + /*std::cout << "TRMM_L: A is not square! Go to Eigen TRMM implementation!\n";*/ \ + } else { \ + /* Make sense to call GEMM */ \ + Map > lhsMap(_lhs,rows,depth,OuterStride<>(lhsStride)); \ + MatrixLhs aa_tmp=lhsMap.template triangularView(); \ + MKL_INT aStride = aa_tmp.outerStride(); \ + gemm_blocking_space blocking(_rows,_cols,_depth); \ + general_matrix_matrix_product::run( \ + rows, cols, depth, aa_tmp.data(), aStride, _rhs, rhsStride, res, resStride, alpha, blocking, 0); \ +\ + /*std::cout << "TRMM_L: A is not square! Go to MKL GEMM implementation! " << nthr<<" \n";*/ \ + } \ + return; \ + } \ + char side = 'L', transa, uplo, diag = 'N'; \ + EIGTYPE *b; \ + const EIGTYPE *a; \ + MKL_INT m, n, lda, ldb; \ + MKLTYPE alpha_; \ +\ +/* Set alpha_*/ \ + assign_scalar_eig2mkl(alpha_, alpha); \ +\ +/* Set m, n */ \ + m = (MKL_INT)diagSize; \ + n = (MKL_INT)cols; \ +\ +/* Set trans */ \ + transa = (LhsStorageOrder==RowMajor) ? ((ConjugateLhs) ? 'C' : 'T') : 'N'; \ +\ +/* Set b, ldb */ \ + Map > rhs(_rhs,depth,cols,OuterStride<>(rhsStride)); \ + MatrixX##EIGPREFIX b_tmp; \ +\ + if (ConjugateRhs) b_tmp = rhs.conjugate(); else b_tmp = rhs; \ + b = b_tmp.data(); \ + ldb = b_tmp.outerStride(); \ +\ +/* Set uplo */ \ + uplo = IsLower ? 'L' : 'U'; \ + if (LhsStorageOrder==RowMajor) uplo = (uplo == 'L') ? 'U' : 'L'; \ +/* Set a, lda */ \ + Map > lhs(_lhs,rows,depth,OuterStride<>(lhsStride)); \ + MatrixLhs a_tmp; \ +\ + if ((conjA!=0) || (SetDiag==0)) { \ + if (conjA) a_tmp = lhs.conjugate(); else a_tmp = lhs; \ + if (IsZeroDiag) \ + a_tmp.diagonal().setZero(); \ + else if (IsUnitDiag) \ + a_tmp.diagonal().setOnes();\ + a = a_tmp.data(); \ + lda = a_tmp.outerStride(); \ + } else { \ + a = _lhs; \ + lda = lhsStride; \ + } \ + /*std::cout << "TRMM_L: A is square! Go to MKL TRMM implementation! \n";*/ \ +/* call ?trmm*/ \ + MKLPREFIX##trmm(&side, &uplo, &transa, &diag, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (MKLTYPE*)b, &ldb); \ +\ +/* Add op(a_triangular)*b into res*/ \ + Map > res_tmp(res,rows,cols,OuterStride<>(resStride)); \ + res_tmp=res_tmp+b_tmp; \ + } \ +}; + +EIGEN_MKL_TRMM_L(double, double, d, d) +EIGEN_MKL_TRMM_L(dcomplex, MKL_Complex16, cd, z) +EIGEN_MKL_TRMM_L(float, float, f, s) +EIGEN_MKL_TRMM_L(scomplex, MKL_Complex8, cf, c) + +// implements col-major += alpha * op(general) * op(triangular) +#define EIGEN_MKL_TRMM_R(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \ +template \ +struct product_triangular_matrix_matrix_trmm \ +{ \ + enum { \ + IsLower = (Mode&Lower) == Lower, \ + SetDiag = (Mode&(ZeroDiag|UnitDiag)) ? 0 : 1, \ + IsUnitDiag = (Mode&UnitDiag) ? 1 : 0, \ + IsZeroDiag = (Mode&ZeroDiag) ? 1 : 0, \ + LowUp = IsLower ? Lower : Upper, \ + conjA = ((RhsStorageOrder==ColMajor) && ConjugateRhs) ? 1 : 0 \ + }; \ +\ + static EIGEN_DONT_INLINE void run( \ + Index _rows, Index _cols, Index _depth, \ + const EIGTYPE* _lhs, Index lhsStride, \ + const EIGTYPE* _rhs, Index rhsStride, \ + EIGTYPE* res, Index resStride, \ + EIGTYPE alpha) \ + { \ + Index diagSize = (std::min)(_cols,_depth); \ + Index rows = _rows; \ + Index depth = IsLower ? _depth : diagSize; \ + Index cols = IsLower ? diagSize : _cols; \ +\ + typedef Matrix MatrixLhs; \ + typedef Matrix MatrixRhs; \ +\ +/* Non-square case - doesn't fit to MKL ?TRMM. Fall to default triangular product or call MKL ?GEMM*/ \ + if (cols != depth) { \ +\ + int nthr = mkl_domain_get_max_threads(MKL_BLAS); \ +\ + if ((nthr==1) && (((std::max)(cols,depth)-diagSize)/(double)diagSize < 0.5)) { \ + /* Most likely no benefit to call TRMM or GEMM from MKL*/ \ + product_triangular_matrix_matrix::run( \ + _rows, _cols, _depth, _lhs, lhsStride, _rhs, rhsStride, res, resStride, alpha); \ + /*std::cout << "TRMM_R: A is not square! Go to Eigen TRMM implementation!\n";*/ \ + } else { \ + /* Make sense to call GEMM */ \ + Map > rhsMap(_rhs,depth,cols, OuterStride<>(rhsStride)); \ + MatrixRhs aa_tmp=rhsMap.template triangularView(); \ + MKL_INT aStride = aa_tmp.outerStride(); \ + gemm_blocking_space blocking(_rows,_cols,_depth); \ + general_matrix_matrix_product::run( \ + rows, cols, depth, _lhs, lhsStride, aa_tmp.data(), aStride, res, resStride, alpha, blocking, 0); \ +\ + /*std::cout << "TRMM_R: A is not square! Go to MKL GEMM implementation! " << nthr<<" \n";*/ \ + } \ + return; \ + } \ + char side = 'R', transa, uplo, diag = 'N'; \ + EIGTYPE *b; \ + const EIGTYPE *a; \ + MKL_INT m, n, lda, ldb; \ + MKLTYPE alpha_; \ +\ +/* Set alpha_*/ \ + assign_scalar_eig2mkl(alpha_, alpha); \ +\ +/* Set m, n */ \ + m = (MKL_INT)rows; \ + n = (MKL_INT)diagSize; \ +\ +/* Set trans */ \ + transa = (RhsStorageOrder==RowMajor) ? ((ConjugateRhs) ? 'C' : 'T') : 'N'; \ +\ +/* Set b, ldb */ \ + Map > lhs(_lhs,rows,depth,OuterStride<>(lhsStride)); \ + MatrixX##EIGPREFIX b_tmp; \ +\ + if (ConjugateLhs) b_tmp = lhs.conjugate(); else b_tmp = lhs; \ + b = b_tmp.data(); \ + ldb = b_tmp.outerStride(); \ +\ +/* Set uplo */ \ + uplo = IsLower ? 'L' : 'U'; \ + if (RhsStorageOrder==RowMajor) uplo = (uplo == 'L') ? 'U' : 'L'; \ +/* Set a, lda */ \ + Map > rhs(_rhs,depth,cols, OuterStride<>(rhsStride)); \ + MatrixRhs a_tmp; \ +\ + if ((conjA!=0) || (SetDiag==0)) { \ + if (conjA) a_tmp = rhs.conjugate(); else a_tmp = rhs; \ + if (IsZeroDiag) \ + a_tmp.diagonal().setZero(); \ + else if (IsUnitDiag) \ + a_tmp.diagonal().setOnes();\ + a = a_tmp.data(); \ + lda = a_tmp.outerStride(); \ + } else { \ + a = _rhs; \ + lda = rhsStride; \ + } \ + /*std::cout << "TRMM_R: A is square! Go to MKL TRMM implementation! \n";*/ \ +/* call ?trmm*/ \ + MKLPREFIX##trmm(&side, &uplo, &transa, &diag, &m, &n, &alpha_, (const MKLTYPE*)a, &lda, (MKLTYPE*)b, &ldb); \ +\ +/* Add op(a_triangular)*b into res*/ \ + Map > res_tmp(res,rows,cols,OuterStride<>(resStride)); \ + res_tmp=res_tmp+b_tmp; \ + } \ +}; + +EIGEN_MKL_TRMM_R(double, double, d, d) +EIGEN_MKL_TRMM_R(dcomplex, MKL_Complex16, cd, z) +EIGEN_MKL_TRMM_R(float, float, f, s) +EIGEN_MKL_TRMM_R(scomplex, MKL_Complex8, cf, c) + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_TRIANGULAR_MATRIX_MATRIX_MKL_H diff --git a/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixVector.h b/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixVector.h index 71b4a52ab80..b1c10c201c5 100644 --- a/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixVector.h +++ b/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixVector.h @@ -3,45 +3,36 @@ // // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_TRIANGULARMATRIXVECTOR_H #define EIGEN_TRIANGULARMATRIXVECTOR_H +namespace Eigen { + namespace internal { -template -struct product_triangular_matrix_vector; +template +struct triangular_matrix_vector_product; -template -struct product_triangular_matrix_vector +template +struct triangular_matrix_vector_product { typedef typename scalar_product_traits::ReturnType ResScalar; enum { IsLower = ((Mode&Lower)==Lower), - HasUnitDiag = (Mode & UnitDiag)==UnitDiag + HasUnitDiag = (Mode & UnitDiag)==UnitDiag, + HasZeroDiag = (Mode & ZeroDiag)==ZeroDiag }; - static EIGEN_DONT_INLINE void run(Index rows, Index cols, const LhsScalar* _lhs, Index lhsStride, + static EIGEN_DONT_INLINE void run(Index _rows, Index _cols, const LhsScalar* _lhs, Index lhsStride, const RhsScalar* _rhs, Index rhsIncr, ResScalar* _res, Index resIncr, ResScalar alpha) { static const Index PanelWidth = EIGEN_TUNE_TRIANGULAR_PANEL_WIDTH; + Index size = (std::min)(_rows,_cols); + Index rows = IsLower ? _rows : (std::min)(_rows,_cols); + Index cols = IsLower ? (std::min)(_rows,_cols) : _cols; typedef Map, 0, OuterStride<> > LhsMap; const LhsMap lhs(_lhs,rows,cols,OuterStride<>(lhsStride)); @@ -54,45 +45,57 @@ struct product_triangular_matrix_vector > ResMap; ResMap res(_res,rows); - for (Index pi=0; pi0) + if ((!(HasUnitDiag||HasZeroDiag)) || (--r)>0) res.segment(s,r) += (alpha * cjRhs.coeff(i)) * cjLhs.col(i).segment(s,r); if (HasUnitDiag) res.coeffRef(i) += alpha * cjRhs.coeff(i); } - Index r = IsLower ? cols - pi - actualPanelWidth : pi; + Index r = IsLower ? rows - pi - actualPanelWidth : pi; if (r>0) { Index s = IsLower ? pi+actualPanelWidth : 0; - general_matrix_vector_product::run( + general_matrix_vector_product::run( r, actualPanelWidth, &lhs.coeffRef(s,pi), lhsStride, &rhs.coeffRef(pi), rhsIncr, &res.coeffRef(s), resIncr, alpha); } } + if((!IsLower) && cols>size) + { + general_matrix_vector_product::run( + rows, cols-size, + &lhs.coeffRef(0,size), lhsStride, + &rhs.coeffRef(size), rhsIncr, + _res, resIncr, alpha); + } } }; -template -struct product_triangular_matrix_vector +template +struct triangular_matrix_vector_product { typedef typename scalar_product_traits::ReturnType ResScalar; enum { IsLower = ((Mode&Lower)==Lower), - HasUnitDiag = (Mode & UnitDiag)==UnitDiag + HasUnitDiag = (Mode & UnitDiag)==UnitDiag, + HasZeroDiag = (Mode & ZeroDiag)==ZeroDiag }; - static void run(Index rows, Index cols, const LhsScalar* _lhs, Index lhsStride, + static void run(Index _rows, Index _cols, const LhsScalar* _lhs, Index lhsStride, const RhsScalar* _rhs, Index rhsIncr, ResScalar* _res, Index resIncr, ResScalar alpha) { static const Index PanelWidth = EIGEN_TUNE_TRIANGULAR_PANEL_WIDTH; + Index diagSize = (std::min)(_rows,_cols); + Index rows = IsLower ? _rows : diagSize; + Index cols = IsLower ? diagSize : _cols; typedef Map, 0, OuterStride<> > LhsMap; const LhsMap lhs(_lhs,rows,cols,OuterStride<>(lhsStride)); @@ -105,15 +108,15 @@ struct product_triangular_matrix_vector, 0, InnerStride<> > ResMap; ResMap res(_res,rows,InnerStride<>(resIncr)); - for (Index pi=0; pi0) + if ((!(HasUnitDiag||HasZeroDiag)) || (--r)>0) res.coeffRef(i) += alpha * (cjLhs.row(i).segment(s,r).cwiseProduct(cjRhs.segment(s,r).transpose())).sum(); if (HasUnitDiag) res.coeffRef(i) += alpha * cjRhs.coeff(i); @@ -122,13 +125,21 @@ struct product_triangular_matrix_vector0) { Index s = IsLower ? 0 : pi + actualPanelWidth; - general_matrix_vector_product::run( + general_matrix_vector_product::run( actualPanelWidth, r, &lhs.coeffRef(pi,s), lhsStride, &rhs.coeffRef(s), rhsIncr, &res.coeffRef(pi), resIncr, alpha); } } + if(IsLower && rows>diagSize) + { + general_matrix_vector_product::run( + rows-diagSize, cols, + &lhs.coeffRef(diagSize,0), lhsStride, + &rhs.coeffRef(0), rhsIncr, + &res.coeffRef(diagSize), resIncr, alpha); + } } }; @@ -180,7 +191,7 @@ struct TriangularProduct { eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); - typedef TriangularProduct<(Mode & UnitDiag) | ((Mode & Lower) ? Upper : Lower),true,Transpose,false,Transpose,true> TriangularProductTranspose; + typedef TriangularProduct<(Mode & (UnitDiag|ZeroDiag)) | ((Mode & Lower) ? Upper : Lower),true,Transpose,false,Transpose,true> TriangularProductTranspose; Transpose dstT(dst); internal::trmv_selector<(int(internal::traits::Flags)&RowMajorBit) ? ColMajor : RowMajor>::run( TriangularProductTranspose(m_rhs.transpose(),m_lhs.transpose()), dstT, alpha); @@ -208,8 +219,8 @@ template<> struct trmv_selector typedef typename ProductType::RhsBlasTraits RhsBlasTraits; typedef Map, Aligned> MappedDest; - const ActualLhsType actualLhs = LhsBlasTraits::extract(prod.lhs()); - const ActualRhsType actualRhs = RhsBlasTraits::extract(prod.rhs()); + typename internal::add_const_on_value_type::type actualLhs = LhsBlasTraits::extract(prod.lhs()); + typename internal::add_const_on_value_type::type actualRhs = RhsBlasTraits::extract(prod.rhs()); ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) * RhsBlasTraits::extractScalarFactor(prod.rhs()); @@ -247,7 +258,7 @@ template<> struct trmv_selector MappedDest(actualDestPtr, dest.size()) = dest; } - internal::product_triangular_matrix_vector + internal::triangular_matrix_vector_product struct trmv_selector Map(actualRhsPtr, actualRhs.size()) = actualRhs; } - internal::product_triangular_matrix_vector + internal::triangular_matrix_vector_product struct trmv_selector } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_TRIANGULARMATRIXVECTOR_H diff --git a/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixVector_MKL.h b/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixVector_MKL.h new file mode 100644 index 00000000000..3589b8c5ef6 --- /dev/null +++ b/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixVector_MKL.h @@ -0,0 +1,247 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * Triangular matrix-vector product functionality based on ?TRMV. + ******************************************************************************** +*/ + +#ifndef EIGEN_TRIANGULAR_MATRIX_VECTOR_MKL_H +#define EIGEN_TRIANGULAR_MATRIX_VECTOR_MKL_H + +namespace Eigen { + +namespace internal { + +/********************************************************************** +* This file implements triangular matrix-vector multiplication using BLAS +**********************************************************************/ + +// trmv/hemv specialization + +template +struct triangular_matrix_vector_product_trmv : + triangular_matrix_vector_product {}; + +#define EIGEN_MKL_TRMV_SPECIALIZE(Scalar) \ +template \ +struct triangular_matrix_vector_product { \ + static EIGEN_DONT_INLINE void run(Index _rows, Index _cols, const Scalar* _lhs, Index lhsStride, \ + const Scalar* _rhs, Index rhsIncr, Scalar* _res, Index resIncr, Scalar alpha) { \ + triangular_matrix_vector_product_trmv::run( \ + _rows, _cols, _lhs, lhsStride, _rhs, rhsIncr, _res, resIncr, alpha); \ + } \ +}; \ +template \ +struct triangular_matrix_vector_product { \ + static EIGEN_DONT_INLINE void run(Index _rows, Index _cols, const Scalar* _lhs, Index lhsStride, \ + const Scalar* _rhs, Index rhsIncr, Scalar* _res, Index resIncr, Scalar alpha) { \ + triangular_matrix_vector_product_trmv::run( \ + _rows, _cols, _lhs, lhsStride, _rhs, rhsIncr, _res, resIncr, alpha); \ + } \ +}; + +EIGEN_MKL_TRMV_SPECIALIZE(double) +EIGEN_MKL_TRMV_SPECIALIZE(float) +EIGEN_MKL_TRMV_SPECIALIZE(dcomplex) +EIGEN_MKL_TRMV_SPECIALIZE(scomplex) + +// implements col-major: res += alpha * op(triangular) * vector +#define EIGEN_MKL_TRMV_CM(EIGTYPE, MKLTYPE, EIGPREFIX, MKLPREFIX) \ +template \ +struct triangular_matrix_vector_product_trmv { \ + enum { \ + IsLower = (Mode&Lower) == Lower, \ + SetDiag = (Mode&(ZeroDiag|UnitDiag)) ? 0 : 1, \ + IsUnitDiag = (Mode&UnitDiag) ? 1 : 0, \ + IsZeroDiag = (Mode&ZeroDiag) ? 1 : 0, \ + LowUp = IsLower ? Lower : Upper \ + }; \ + static EIGEN_DONT_INLINE void run(Index _rows, Index _cols, const EIGTYPE* _lhs, Index lhsStride, \ + const EIGTYPE* _rhs, Index rhsIncr, EIGTYPE* _res, Index resIncr, EIGTYPE alpha, level3_blocking& blocking) \ + { \ + if (ConjLhs || IsZeroDiag) { \ + triangular_matrix_vector_product::run( \ + _rows, _cols, _lhs, lhsStride, _rhs, rhsIncr, _res, resIncr, alpha, blocking); \ + return; \ + }\ + Index size = (std::min)(_rows,_cols); \ + Index rows = IsLower ? _rows : size; \ + Index cols = IsLower ? size : _cols; \ +\ + typedef VectorX##EIGPREFIX VectorRhs; \ + EIGTYPE *x, *y;\ +\ +/* Set x*/ \ + Map > rhs(_rhs,cols,InnerStride<>(rhsIncr)); \ + VectorRhs x_tmp; \ + if (ConjRhs) x_tmp = rhs.conjugate(); else x_tmp = rhs; \ + x = x_tmp.data(); \ +\ +/* Square part handling */\ +\ + char trans, uplo, diag; \ + MKL_INT m, n, lda, incx, incy; \ + EIGTYPE const *a; \ + MKLTYPE alpha_, beta_; \ + assign_scalar_eig2mkl(alpha_, alpha); \ + assign_scalar_eig2mkl(beta_, EIGTYPE(1)); \ +\ +/* Set m, n */ \ + n = (MKL_INT)size; \ + lda = lhsStride; \ + incx = 1; \ + incy = resIncr; \ +\ +/* Set uplo, trans and diag*/ \ + trans = 'N'; \ + uplo = IsLower ? 'L' : 'U'; \ + diag = IsUnitDiag ? 'U' : 'N'; \ +\ +/* call ?TRMV*/ \ + MKLPREFIX##trmv(&uplo, &trans, &diag, &n, (const MKLTYPE*)_lhs, &lda, (MKLTYPE*)x, &incx); \ +\ +/* Add op(a_tr)rhs into res*/ \ + MKLPREFIX##axpy(&n, &alpha_,(const MKLTYPE*)x, &incx, (MKLTYPE*)_res, &incy); \ +/* Non-square case - doesn't fit to MKL ?TRMV. Fall to default triangular product*/ \ + if (size<(std::max)(rows,cols)) { \ + typedef Matrix MatrixLhs; \ + if (ConjRhs) x_tmp = rhs.conjugate(); else x_tmp = rhs; \ + x = x_tmp.data(); \ + if (size \ +struct triangular_matrix_vector_product_trmv { \ + enum { \ + IsLower = (Mode&Lower) == Lower, \ + SetDiag = (Mode&(ZeroDiag|UnitDiag)) ? 0 : 1, \ + IsUnitDiag = (Mode&UnitDiag) ? 1 : 0, \ + IsZeroDiag = (Mode&ZeroDiag) ? 1 : 0, \ + LowUp = IsLower ? Lower : Upper \ + }; \ + static EIGEN_DONT_INLINE void run(Index _rows, Index _cols, const EIGTYPE* _lhs, Index lhsStride, \ + const EIGTYPE* _rhs, Index rhsIncr, EIGTYPE* _res, Index resIncr, EIGTYPE alpha, level3_blocking& blocking) \ + { \ + if (IsZeroDiag) { \ + triangular_matrix_vector_product::run( \ + _rows, _cols, _lhs, lhsStride, _rhs, rhsIncr, _res, resIncr, alpha, blocking); \ + return; \ + }\ + Index size = (std::min)(_rows,_cols); \ + Index rows = IsLower ? _rows : size; \ + Index cols = IsLower ? size : _cols; \ +\ + typedef VectorX##EIGPREFIX VectorRhs; \ + EIGTYPE *x, *y;\ +\ +/* Set x*/ \ + Map > rhs(_rhs,cols,InnerStride<>(rhsIncr)); \ + VectorRhs x_tmp; \ + if (ConjRhs) x_tmp = rhs.conjugate(); else x_tmp = rhs; \ + x = x_tmp.data(); \ +\ +/* Square part handling */\ +\ + char trans, uplo, diag; \ + MKL_INT m, n, lda, incx, incy; \ + EIGTYPE const *a; \ + MKLTYPE alpha_, beta_; \ + assign_scalar_eig2mkl(alpha_, alpha); \ + assign_scalar_eig2mkl(beta_, EIGTYPE(1)); \ +\ +/* Set m, n */ \ + n = (MKL_INT)size; \ + lda = lhsStride; \ + incx = 1; \ + incy = resIncr; \ +\ +/* Set uplo, trans and diag*/ \ + trans = ConjLhs ? 'C' : 'T'; \ + uplo = IsLower ? 'U' : 'L'; \ + diag = IsUnitDiag ? 'U' : 'N'; \ +\ +/* call ?TRMV*/ \ + MKLPREFIX##trmv(&uplo, &trans, &diag, &n, (const MKLTYPE*)_lhs, &lda, (MKLTYPE*)x, &incx); \ +\ +/* Add op(a_tr)rhs into res*/ \ + MKLPREFIX##axpy(&n, &alpha_,(const MKLTYPE*)x, &incx, (MKLTYPE*)_res, &incy); \ +/* Non-square case - doesn't fit to MKL ?TRMV. Fall to default triangular product*/ \ + if (size<(std::max)(rows,cols)) { \ + typedef Matrix MatrixLhs; \ + if (ConjRhs) x_tmp = rhs.conjugate(); else x_tmp = rhs; \ + x = x_tmp.data(); \ + if (size // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_TRIANGULAR_SOLVER_MATRIX_H #define EIGEN_TRIANGULAR_SOLVER_MATRIX_H +namespace Eigen { + namespace internal { // if the rhs is row major, let's transpose the product @@ -34,14 +21,15 @@ struct triangular_solve_matrix& blocking) { triangular_solve_matrix< Scalar, Index, Side==OnTheLeft?OnTheRight:OnTheLeft, (Mode&UnitDiag) | ((Mode&Upper) ? Lower : Upper), NumTraits::IsComplex && Conjugate, TriStorageOrder==RowMajor ? ColMajor : RowMajor, ColMajor> - ::run(size, cols, tri, triStride, _other, otherStride); + ::run(size, cols, tri, triStride, _other, otherStride, blocking); } }; @@ -53,7 +41,8 @@ struct triangular_solve_matrix& blocking) { Index cols = otherSize; const_blas_data_mapper tri(_tri,triStride); @@ -65,22 +54,29 @@ struct triangular_solve_matrix(kc, mc, nc); + Index kc = blocking.kc(); // cache block size along the K direction + Index mc = (std::min)(size,blocking.mc()); // cache block size along the M direction + std::size_t sizeA = kc*mc; + std::size_t sizeB = kc*cols; std::size_t sizeW = kc*Traits::WorkSpaceFactor; - std::size_t sizeB = sizeW + kc*cols; - ei_declare_aligned_stack_constructed_variable(Scalar, blockA, kc*mc, 0); - ei_declare_aligned_stack_constructed_variable(Scalar, allocatedBlockB, sizeB, 0); - Scalar* blockB = allocatedBlockB + sizeW; + + ei_declare_aligned_stack_constructed_variable(Scalar, blockA, sizeA, blocking.blockA()); + ei_declare_aligned_stack_constructed_variable(Scalar, blockB, sizeB, blocking.blockB()); + ei_declare_aligned_stack_constructed_variable(Scalar, blockW, sizeW, blocking.blockW()); conj_if conj; gebp_kernel gebp_kernel; gemm_pack_lhs pack_lhs; gemm_pack_rhs pack_rhs; + // the goal here is to subdivise the Rhs panels such that we keep some cache + // coherence when accessing the rhs elements + std::ptrdiff_t l1, l2; + manage_caching_sizes(GetAction, &l1, &l2); + Index subcols = cols>0 ? l2/(4 * sizeof(Scalar) * otherStride) : 0; + subcols = std::max((subcols/Traits::nr)*Traits::nr, Traits::nr); + for(Index k2=IsLower ? 0 : size; IsLower ? k20; IsLower ? k2+=kc : k2-=kc) @@ -92,16 +88,18 @@ struct triangular_solve_matrix general block copy (done during the next step) - // - R1 = L1^-1 B => tricky part + // - R1 = A11^-1 B => tricky part // - update B from the new R1 => actually this has to be performed continuously during the above step - // - R2 = L2 * B => GEPP + // - R2 -= A21 * B => GEPP - // The tricky part: compute R1 = L1^-1 B while updating B from R1 - // The idea is to split L1 into multiple small vertical panels. - // Each panel can be split into a small triangular part A1 which is processed without optimization, - // and the remaining small part A2 which is processed using gebp with appropriate block strides + // The tricky part: compute R1 = A11^-1 B while updating B from R1 + // The idea is to split A11 into multiple small vertical panels. + // Each panel can be split into a small triangular part T1k which is processed without optimization, + // and the remaining small part T2k which is processed using gebp with appropriate block strides + for(Index j2=0; j2(actual_kc-k1, SmallPanelWidth); @@ -114,11 +112,11 @@ struct triangular_solve_matrix0) @@ -152,13 +150,13 @@ struct triangular_solve_matrix GEPP + + // R2 -= A21 * B => GEPP { Index start = IsLower ? k2+kc : 0; Index end = IsLower ? size : k2-kc; @@ -169,7 +167,7 @@ struct triangular_solve_matrix& blocking) { Index rows = otherSize; const_blas_data_mapper rhs(_tri,triStride); @@ -198,19 +197,16 @@ struct triangular_solve_matrix(Traits::Max_kc/4,size); // cache block size along the K direction -// Index mc = std::min(Traits::Max_mc,size); // cache block size along the M direction - // check that !!!! - Index kc = size; // cache block size along the K direction - Index mc = size; // cache block size along the M direction - Index nc = rows; // cache block size along the N direction - computeProductBlockingSizes(kc, mc, nc); + Index kc = blocking.kc(); // cache block size along the K direction + Index mc = (std::min)(rows,blocking.mc()); // cache block size along the M direction + std::size_t sizeA = kc*mc; + std::size_t sizeB = kc*size; std::size_t sizeW = kc*Traits::WorkSpaceFactor; - std::size_t sizeB = sizeW + kc*size; - ei_declare_aligned_stack_constructed_variable(Scalar, blockA, kc*mc, 0); - ei_declare_aligned_stack_constructed_variable(Scalar, allocatedBlockB, sizeB, 0); - Scalar* blockB = allocatedBlockB + sizeW; + + ei_declare_aligned_stack_constructed_variable(Scalar, blockA, sizeA, blocking.blockA()); + ei_declare_aligned_stack_constructed_variable(Scalar, blockB, sizeB, blocking.blockB()); + ei_declare_aligned_stack_constructed_variable(Scalar, blockW, sizeW, blocking.blockW()); conj_if conj; gebp_kernel gebp_kernel; @@ -277,7 +273,7 @@ struct triangular_solve_matrix0) gebp_kernel(_other+i2+startPanel*otherStride, otherStride, blockA, geb, actual_mc, actual_kc, rs, Scalar(-1), - -1, -1, 0, 0, allocatedBlockB); + -1, -1, 0, 0, blockW); } } } @@ -316,4 +312,6 @@ struct triangular_solve_matrix \ +struct triangular_solve_matrix \ +{ \ + enum { \ + IsLower = (Mode&Lower) == Lower, \ + IsUnitDiag = (Mode&UnitDiag) ? 1 : 0, \ + IsZeroDiag = (Mode&ZeroDiag) ? 1 : 0, \ + conjA = ((TriStorageOrder==ColMajor) && Conjugate) ? 1 : 0 \ + }; \ + static EIGEN_DONT_INLINE void run( \ + Index size, Index otherSize, \ + const EIGTYPE* _tri, Index triStride, \ + EIGTYPE* _other, Index otherStride, level3_blocking& /*blocking*/) \ + { \ + MKL_INT m = size, n = otherSize, lda, ldb; \ + char side = 'L', uplo, diag='N', transa; \ + /* Set alpha_ */ \ + MKLTYPE alpha; \ + EIGTYPE myone(1); \ + assign_scalar_eig2mkl(alpha, myone); \ + ldb = otherStride;\ +\ + const EIGTYPE *a; \ +/* Set trans */ \ + transa = (TriStorageOrder==RowMajor) ? ((Conjugate) ? 'C' : 'T') : 'N'; \ +/* Set uplo */ \ + uplo = IsLower ? 'L' : 'U'; \ + if (TriStorageOrder==RowMajor) uplo = (uplo == 'L') ? 'U' : 'L'; \ +/* Set a, lda */ \ + typedef Matrix MatrixTri; \ + Map > tri(_tri,size,size,OuterStride<>(triStride)); \ + MatrixTri a_tmp; \ +\ + if (conjA) { \ + a_tmp = tri.conjugate(); \ + a = a_tmp.data(); \ + lda = a_tmp.outerStride(); \ + } else { \ + a = _tri; \ + lda = triStride; \ + } \ + if (IsUnitDiag) diag='U'; \ +/* call ?trsm*/ \ + MKLPREFIX##trsm(&side, &uplo, &transa, &diag, &m, &n, &alpha, (const MKLTYPE*)a, &lda, (MKLTYPE*)_other, &ldb); \ + } \ +}; + +EIGEN_MKL_TRSM_L(double, double, d) +EIGEN_MKL_TRSM_L(dcomplex, MKL_Complex16, z) +EIGEN_MKL_TRSM_L(float, float, s) +EIGEN_MKL_TRSM_L(scomplex, MKL_Complex8, c) + + +// implements RightSide general * op(triangular)^-1 +#define EIGEN_MKL_TRSM_R(EIGTYPE, MKLTYPE, MKLPREFIX) \ +template \ +struct triangular_solve_matrix \ +{ \ + enum { \ + IsLower = (Mode&Lower) == Lower, \ + IsUnitDiag = (Mode&UnitDiag) ? 1 : 0, \ + IsZeroDiag = (Mode&ZeroDiag) ? 1 : 0, \ + conjA = ((TriStorageOrder==ColMajor) && Conjugate) ? 1 : 0 \ + }; \ + static EIGEN_DONT_INLINE void run( \ + Index size, Index otherSize, \ + const EIGTYPE* _tri, Index triStride, \ + EIGTYPE* _other, Index otherStride, level3_blocking& /*blocking*/) \ + { \ + MKL_INT m = otherSize, n = size, lda, ldb; \ + char side = 'R', uplo, diag='N', transa; \ + /* Set alpha_ */ \ + MKLTYPE alpha; \ + EIGTYPE myone(1); \ + assign_scalar_eig2mkl(alpha, myone); \ + ldb = otherStride;\ +\ + const EIGTYPE *a; \ +/* Set trans */ \ + transa = (TriStorageOrder==RowMajor) ? ((Conjugate) ? 'C' : 'T') : 'N'; \ +/* Set uplo */ \ + uplo = IsLower ? 'L' : 'U'; \ + if (TriStorageOrder==RowMajor) uplo = (uplo == 'L') ? 'U' : 'L'; \ +/* Set a, lda */ \ + typedef Matrix MatrixTri; \ + Map > tri(_tri,size,size,OuterStride<>(triStride)); \ + MatrixTri a_tmp; \ +\ + if (conjA) { \ + a_tmp = tri.conjugate(); \ + a = a_tmp.data(); \ + lda = a_tmp.outerStride(); \ + } else { \ + a = _tri; \ + lda = triStride; \ + } \ + if (IsUnitDiag) diag='U'; \ +/* call ?trsm*/ \ + MKLPREFIX##trsm(&side, &uplo, &transa, &diag, &m, &n, &alpha, (const MKLTYPE*)a, &lda, (MKLTYPE*)_other, &ldb); \ + /*std::cout << "TRMS_L specialization!\n";*/ \ + } \ +}; + +EIGEN_MKL_TRSM_R(double, double, d) +EIGEN_MKL_TRSM_R(dcomplex, MKL_Complex16, z) +EIGEN_MKL_TRSM_R(float, float, s) +EIGEN_MKL_TRSM_R(scomplex, MKL_Complex8, c) + + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_TRIANGULAR_SOLVER_MATRIX_MKL_H diff --git a/extern/Eigen3/Eigen/src/Core/products/TriangularSolverVector.h b/extern/Eigen3/Eigen/src/Core/products/TriangularSolverVector.h index 639d4a5b476..ce4d1008801 100644 --- a/extern/Eigen3/Eigen/src/Core/products/TriangularSolverVector.h +++ b/extern/Eigen3/Eigen/src/Core/products/TriangularSolverVector.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_TRIANGULAR_SOLVER_VECTOR_H #define EIGEN_TRIANGULAR_SOLVER_VECTOR_H +namespace Eigen { + namespace internal { template @@ -147,4 +134,6 @@ struct triangular_solve_vector // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_BLASUTIL_H #define EIGEN_BLASUTIL_H @@ -28,6 +13,8 @@ // This file contains many lightweight helper classes used to // implement and control fast level 2 and level 3 BLAS-like routines. +namespace Eigen { + namespace internal { // forward declarations @@ -47,7 +34,7 @@ template< int ResStorageOrder> struct general_matrix_matrix_product; -template +template struct general_matrix_vector_product; @@ -56,11 +43,15 @@ template struct conj_if; template<> struct conj_if { template inline T operator()(const T& x) { return conj(x); } + template + inline T pconj(const T& x) { return internal::pconj(x); } }; template<> struct conj_if { template inline const T& operator()(const T& x) { return x; } + template + inline const T& pconj(const T& x) { return x; } }; template struct conj_helper @@ -118,11 +109,11 @@ template struct conj_helper struct get_factor { - EIGEN_STRONG_INLINE static To run(const From& x) { return x; } + static EIGEN_STRONG_INLINE To run(const From& x) { return x; } }; template struct get_factor::Real> { - EIGEN_STRONG_INLINE static typename NumTraits::Real run(const Scalar& x) { return real(x); } + static EIGEN_STRONG_INLINE typename NumTraits::Real run(const Scalar& x) { return real(x); } }; // Lightweight helper class to access matrix coefficients. @@ -175,7 +166,7 @@ template struct blas_traits ExtractType, typename _ExtractType::PlainObject >::type DirectLinearAccessType; - static inline const ExtractType extract(const XprType& x) { return x; } + static inline ExtractType extract(const XprType& x) { return x; } static inline const Scalar extractScalarFactor(const XprType&) { return Scalar(1); } }; @@ -192,7 +183,7 @@ struct blas_traits, NestedXpr> > IsComplex = NumTraits::IsComplex, NeedToConjugate = Base::NeedToConjugate ? 0 : IsComplex }; - static inline const ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); } + static inline ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); } static inline Scalar extractScalarFactor(const XprType& x) { return conj(Base::extractScalarFactor(x.nestedExpression())); } }; @@ -204,7 +195,7 @@ struct blas_traits, NestedXpr> > typedef blas_traits Base; typedef CwiseUnaryOp, NestedXpr> XprType; typedef typename Base::ExtractType ExtractType; - static inline const ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); } + static inline ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); } static inline Scalar extractScalarFactor(const XprType& x) { return x.functor().m_other * Base::extractScalarFactor(x.nestedExpression()); } }; @@ -217,7 +208,7 @@ struct blas_traits, NestedXpr> > typedef blas_traits Base; typedef CwiseUnaryOp, NestedXpr> XprType; typedef typename Base::ExtractType ExtractType; - static inline const ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); } + static inline ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); } static inline Scalar extractScalarFactor(const XprType& x) { return - Base::extractScalarFactor(x.nestedExpression()); } }; @@ -239,7 +230,7 @@ struct blas_traits > enum { IsTransposed = Base::IsTransposed ? 0 : 1 }; - static inline const ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); } + static inline ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); } static inline Scalar extractScalarFactor(const XprType& x) { return Base::extractScalarFactor(x.nestedExpression()); } }; @@ -252,7 +243,7 @@ template::HasUsableDirectA struct extract_data_selector { static const typename T::Scalar* run(const T& m) { - return const_cast(&blas_traits::extract(m).coeffRef(0,0)); // FIXME this should be .data() + return blas_traits::extract(m).data(); } }; @@ -268,4 +259,6 @@ template const typename T::Scalar* extract_data(const T& m) } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_BLASUTIL_H diff --git a/extern/Eigen3/Eigen/src/Core/util/Constants.h b/extern/Eigen3/Eigen/src/Core/util/Constants.h index c3dd3a09d00..3fd45e84f8e 100644 --- a/extern/Eigen3/Eigen/src/Core/util/Constants.h +++ b/extern/Eigen3/Eigen/src/Core/util/Constants.h @@ -4,28 +4,15 @@ // Copyright (C) 2008-2009 Gael Guennebaud // Copyright (C) 2007-2009 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CONSTANTS_H #define EIGEN_CONSTANTS_H +namespace Eigen { + /** This value means that a quantity is not known at compile-time, and that instead the value is * stored in some runtime variable. * @@ -188,7 +175,9 @@ enum { /** View matrix as an upper triangular matrix with zeros on the diagonal. */ StrictlyUpper=ZeroDiag|Upper, /** Used in BandMatrix and SelfAdjointView to indicate that the matrix is self-adjoint. */ - SelfAdjoint=0x10 + SelfAdjoint=0x10, + /** Used to support symmetric, non-selfadjoint, complex matrices. */ + Symmetric=0x20 }; /** \ingroup enums @@ -200,8 +189,6 @@ enum { Aligned=1 }; -enum { ConditionalJumpCost = 5 }; - /** \ingroup enums * Enum used by DenseBase::corner() in Eigen2 compatibility mode. */ // FIXME after the corner() API change, this was not needed anymore, except by AlignedBox @@ -223,8 +210,6 @@ enum DirectionType { BothDirections }; -enum ProductEvaluationMode { NormalProduct, CacheFriendlyProduct }; - /** \internal \ingroup enums * Enum to specify how to traverse the entries of a matrix. */ enum { @@ -257,6 +242,13 @@ enum { CompleteUnrolling }; +/** \internal \ingroup enums + * Enum to specify whether to use the default (built-in) implementation or the specialization. */ +enum { + Specialized, + BuiltIn +}; + /** \ingroup enums * Enum containing possible values for the \p _Options template parameter of * Matrix, Array and BandMatrix. */ @@ -280,26 +272,21 @@ enum { OnTheRight = 2 }; -/* the following could as well be written: - * enum NoChange_t { NoChange }; - * but it feels dangerous to disambiguate overloaded functions on enum/integer types. - * If on some platform it is really impossible to get rid of "unused variable" warnings, then - * we can always come back to that solution. +/* the following used to be written as: + * + * struct NoChange_t {}; + * namespace { + * EIGEN_UNUSED NoChange_t NoChange; + * } + * + * on the ground that it feels dangerous to disambiguate overloaded functions on enum/integer types. + * However, this leads to "variable declared but never referenced" warnings on Intel Composer XE, + * and we do not know how to get rid of them (bug 450). */ -struct NoChange_t {}; -namespace { - EIGEN_UNUSED NoChange_t NoChange; -} - -struct Sequential_t {}; -namespace { - EIGEN_UNUSED Sequential_t Sequential; -} -struct Default_t {}; -namespace { - EIGEN_UNUSED Default_t Default; -} +enum NoChange_t { NoChange }; +enum Sequential_t { Sequential }; +enum Default_t { Default }; /** \internal \ingroup enums * Used in AmbiVector. */ @@ -375,7 +362,7 @@ enum QRPreconditioners { #error The preprocessor symbol 'Success' is defined, possibly by the X11 header file X.h #endif -/** \ingroups enums +/** \ingroup enums * Enum for reporting the status of a computation. */ enum ComputationInfo { /** Computation was successful. */ @@ -383,7 +370,10 @@ enum ComputationInfo { /** The provided data did not satisfy the prerequisites. */ NumericalIssue = 1, /** Iterative procedure did not converge. */ - NoConvergence = 2 + NoConvergence = 2, + /** The inputs are invalid, or the algorithm has been improperly called. + * When assertions are enabled, such errors trigger an assert. */ + InvalidInput = 3 }; /** \ingroup enums @@ -436,4 +426,6 @@ struct MatrixXpr {}; /** The type used to identify an array expression */ struct ArrayXpr {}; +} // end namespace Eigen + #endif // EIGEN_CONSTANTS_H diff --git a/extern/Eigen3/Eigen/src/Core/util/DisableStupidWarnings.h b/extern/Eigen3/Eigen/src/Core/util/DisableStupidWarnings.h index 00730524b26..6a0bf0629c5 100644 --- a/extern/Eigen3/Eigen/src/Core/util/DisableStupidWarnings.h +++ b/extern/Eigen3/Eigen/src/Core/util/DisableStupidWarnings.h @@ -21,15 +21,13 @@ #elif defined __INTEL_COMPILER // 2196 - routine is both "inline" and "noinline" ("noinline" assumed) // ICC 12 generates this warning even without any inline keyword, when defining class methods 'inline' i.e. inside of class body - // 2536 - type qualifiers are meaningless here - // ICC 12 generates this warning when a function return type is const qualified, even if that type is a template-parameter-dependent // typedef that may be a reference type. // 279 - controlling expression is constant // ICC 12 generates this warning on assert(constant_expression_depending_on_template_params) and frankly this is a legitimate use case. #ifndef EIGEN_PERMANENTLY_DISABLE_STUPID_WARNINGS #pragma warning push #endif - #pragma warning disable 2196 2536 279 + #pragma warning disable 2196 279 #elif defined __clang__ // -Wconstant-logical-operand - warning: use of logical && with constant operand; switch to bitwise & or remove constant // this is really a stupid warning as it warns on compile-time expressions involving enums diff --git a/extern/Eigen3/Eigen/src/Core/util/ForwardDeclarations.h b/extern/Eigen3/Eigen/src/Core/util/ForwardDeclarations.h index 7fbccf98c2b..bcdfe3914e3 100644 --- a/extern/Eigen3/Eigen/src/Core/util/ForwardDeclarations.h +++ b/extern/Eigen3/Eigen/src/Core/util/ForwardDeclarations.h @@ -4,28 +4,14 @@ // Copyright (C) 2007-2010 Benoit Jacob // Copyright (C) 2008-2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_FORWARDDECLARATIONS_H #define EIGEN_FORWARDDECLARATIONS_H +namespace Eigen { namespace internal { template struct traits; @@ -133,6 +119,7 @@ template class WithFormat; template struct CommaInitializer; template class ReturnByValue; template class ArrayWrapper; +template class MatrixWrapper; namespace internal { template struct solve_retval_base; @@ -282,6 +269,8 @@ template class Homogeneous; // MatrixFunctions module template struct MatrixExponentialReturnValue; template class MatrixFunctionReturnValue; +template class MatrixSquareRootReturnValue; +template class MatrixLogarithmReturnValue; namespace internal { template @@ -304,4 +293,6 @@ template struct eigen2_part_return_type; } #endif +} // end namespace Eigen + #endif // EIGEN_FORWARDDECLARATIONS_H diff --git a/extern/Eigen3/Eigen/src/Core/util/MKL_support.h b/extern/Eigen3/Eigen/src/Core/util/MKL_support.h new file mode 100644 index 00000000000..1e6e355d626 --- /dev/null +++ b/extern/Eigen3/Eigen/src/Core/util/MKL_support.h @@ -0,0 +1,109 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * Include file with common MKL declarations + ******************************************************************************** +*/ + +#ifndef EIGEN_MKL_SUPPORT_H +#define EIGEN_MKL_SUPPORT_H + +#ifdef EIGEN_USE_MKL_ALL + #ifndef EIGEN_USE_BLAS + #define EIGEN_USE_BLAS + #endif + #ifndef EIGEN_USE_LAPACKE + #define EIGEN_USE_LAPACKE + #endif + #ifndef EIGEN_USE_MKL_VML + #define EIGEN_USE_MKL_VML + #endif +#endif + +#ifdef EIGEN_USE_LAPACKE_STRICT + #define EIGEN_USE_LAPACKE +#endif + +#if defined(EIGEN_USE_BLAS) || defined(EIGEN_USE_LAPACKE) || defined(EIGEN_USE_MKL_VML) + #define EIGEN_USE_MKL +#endif + +#if defined EIGEN_USE_MKL + +#include +#include +#define EIGEN_MKL_VML_THRESHOLD 128 + +namespace Eigen { + +typedef std::complex dcomplex; +typedef std::complex scomplex; + +namespace internal { + +template +static inline void assign_scalar_eig2mkl(MKLType& mklScalar, const EigenType& eigenScalar) { + mklScalar=eigenScalar; +} + +template +static inline void assign_conj_scalar_eig2mkl(MKLType& mklScalar, const EigenType& eigenScalar) { + mklScalar=eigenScalar; +} + +template <> +inline void assign_scalar_eig2mkl(MKL_Complex16& mklScalar, const dcomplex& eigenScalar) { + mklScalar.real=eigenScalar.real(); + mklScalar.imag=eigenScalar.imag(); +} + +template <> +inline void assign_scalar_eig2mkl(MKL_Complex8& mklScalar, const scomplex& eigenScalar) { + mklScalar.real=eigenScalar.real(); + mklScalar.imag=eigenScalar.imag(); +} + +template <> +inline void assign_conj_scalar_eig2mkl(MKL_Complex16& mklScalar, const dcomplex& eigenScalar) { + mklScalar.real=eigenScalar.real(); + mklScalar.imag=-eigenScalar.imag(); +} + +template <> +inline void assign_conj_scalar_eig2mkl(MKL_Complex8& mklScalar, const scomplex& eigenScalar) { + mklScalar.real=eigenScalar.real(); + mklScalar.imag=-eigenScalar.imag(); +} + +} // end namespace internal + +} // end namespace Eigen + +#endif + +#endif // EIGEN_MKL_SUPPORT_H diff --git a/extern/Eigen3/Eigen/src/Core/util/Macros.h b/extern/Eigen3/Eigen/src/Core/util/Macros.h index b7c2b79af92..d973a68372f 100644 --- a/extern/Eigen3/Eigen/src/Core/util/Macros.h +++ b/extern/Eigen3/Eigen/src/Core/util/Macros.h @@ -1,35 +1,19 @@ - // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MACROS_H #define EIGEN_MACROS_H #define EIGEN_WORLD_VERSION 3 -#define EIGEN_MAJOR_VERSION 0 -#define EIGEN_MINOR_VERSION 5 +#define EIGEN_MAJOR_VERSION 1 +#define EIGEN_MINOR_VERSION 1 #define EIGEN_VERSION_AT_LEAST(x,y,z) (EIGEN_WORLD_VERSION>x || (EIGEN_WORLD_VERSION>=x && \ (EIGEN_MAJOR_VERSION>y || (EIGEN_MAJOR_VERSION>=y && \ @@ -235,12 +219,16 @@ #define EIGEN_ONLY_USED_FOR_DEBUG(x) #endif -#if (defined __GNUC__) -#define EIGEN_DEPRECATED __attribute__((deprecated)) -#elif (defined _MSC_VER) -#define EIGEN_DEPRECATED __declspec(deprecated) +#ifndef EIGEN_NO_DEPRECATED_WARNING + #if (defined __GNUC__) + #define EIGEN_DEPRECATED __attribute__((deprecated)) + #elif (defined _MSC_VER) + #define EIGEN_DEPRECATED __declspec(deprecated) + #else + #define EIGEN_DEPRECATED + #endif #else -#define EIGEN_DEPRECATED + #define EIGEN_DEPRECATED #endif #if (defined __GNUC__) @@ -252,7 +240,7 @@ // Suppresses 'unused variable' warnings. #define EIGEN_UNUSED_VARIABLE(var) (void)var; -#if (defined __GNUC__) +#if !defined(EIGEN_ASM_COMMENT) && (defined __GNUC__) #define EIGEN_ASM_COMMENT(X) asm("#" X) #else #define EIGEN_ASM_COMMENT(X) @@ -265,7 +253,7 @@ * If we made alignment depend on whether or not EIGEN_VECTORIZE is defined, it would be impossible to link * vectorized and non-vectorized code. */ -#if (defined __GNUC__) || (defined __PGI) || (defined __IBMCPP__) +#if (defined __GNUC__) || (defined __PGI) || (defined __IBMCPP__) || (defined __ARMCC_VERSION) #define EIGEN_ALIGN_TO_BOUNDARY(n) __attribute__((aligned(n))) #elif (defined _MSC_VER) #define EIGEN_ALIGN_TO_BOUNDARY(n) __declspec(align(n)) diff --git a/extern/Eigen3/Eigen/src/Core/util/Memory.h b/extern/Eigen3/Eigen/src/Core/util/Memory.h index 023716dc9e0..6e06ace44a0 100644 --- a/extern/Eigen3/Eigen/src/Core/util/Memory.h +++ b/extern/Eigen3/Eigen/src/Core/util/Memory.h @@ -7,24 +7,9 @@ // Copyright (C) 2010 Hauke Heibel // Copyright (C) 2010 Thomas Capricelli // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. /***************************************************************************** @@ -80,6 +65,8 @@ #define EIGEN_HAS_MM_MALLOC 0 #endif +namespace Eigen { + namespace internal { inline void throw_std_bad_alloc() @@ -457,7 +444,7 @@ template inline void conditional_aligned_delete_auto(T * * There is also the variant first_aligned(const MatrixBase&) defined in DenseCoeffsBase.h. */ template -inline static Index first_aligned(const Scalar* array, Index size) +static inline Index first_aligned(const Scalar* array, Index size) { typedef typename packet_traits::type Packet; enum { PacketSize = packet_traits::size, @@ -483,7 +470,26 @@ inline static Index first_aligned(const Scalar* array, Index size) } } -} // end namespace internal + +// std::copy is much slower than memcpy, so let's introduce a smart_copy which +// use memcpy on trivial types, i.e., on types that does not require an initialization ctor. +template struct smart_copy_helper; + +template void smart_copy(const T* start, const T* end, T* target) +{ + smart_copy_helper::RequireInitialization>::run(start, end, target); +} + +template struct smart_copy_helper { + static inline void run(const T* start, const T* end, T* target) + { memcpy(target, start, std::ptrdiff_t(end)-std::ptrdiff_t(start)); } +}; + +template struct smart_copy_helper { + static inline void run(const T* start, const T* end, T* target) + { std::copy(start, end, target); } +}; + /***************************************************************************** *** Implementation of runtime stack allocation (falling back to malloc) *** @@ -499,8 +505,6 @@ inline static Index first_aligned(const Scalar* array, Index size) #endif #endif -namespace internal { - // This helper class construct the allocated memory, and takes care of destructing and freeing the handled data // at destruction time. In practice this helper class is mainly useful to avoid memory leak in case of exceptions. template class aligned_stack_memory_handler @@ -531,14 +535,14 @@ template class aligned_stack_memory_handler bool m_deallocate; }; -} +} // end namespace internal /** \internal * Declares, allocates and construct an aligned buffer named NAME of SIZE elements of type TYPE on the stack * if SIZE is smaller than EIGEN_STACK_ALLOCATION_LIMIT, and if stack allocation is supported by the platform * (currently, this is Linux and Visual Studio only). Otherwise the memory is allocated on the heap. * The allocated buffer is automatically deleted when exiting the scope of this declaration. - * If BUFFER is non nul, then the declared variable is simply an alias for BUFFER, and no allocation/deletion occurs. + * If BUFFER is non null, then the declared variable is simply an alias for BUFFER, and no allocation/deletion occurs. * Here is an example: * \code * { @@ -619,7 +623,7 @@ template class aligned_stack_memory_handler #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(true) #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar,Size) \ - EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(((Size)!=Eigen::Dynamic) && ((sizeof(Scalar)*(Size))%16==0)) + EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(bool(((Size)!=Eigen::Dynamic) && ((sizeof(Scalar)*(Size))%16==0))) /****************************************************************************/ @@ -667,24 +671,24 @@ public: return &value; } - aligned_allocator() throw() + aligned_allocator() { } - aligned_allocator( const aligned_allocator& ) throw() + aligned_allocator( const aligned_allocator& ) { } template - aligned_allocator( const aligned_allocator& ) throw() + aligned_allocator( const aligned_allocator& ) { } - ~aligned_allocator() throw() + ~aligned_allocator() { } - size_type max_size() const throw() + size_type max_size() const { return (std::numeric_limits::max)(); } @@ -701,6 +705,15 @@ public: ::new( p ) T( value ); } + // Support for c++11 +#if (__cplusplus >= 201103L) + template + void construct(pointer p, Args&&... args) + { + ::new(p) T(std::forward(args)...); + } +#endif + void destroy( pointer p ) { p->~T(); @@ -720,19 +733,21 @@ public: //---------- Cache sizes ---------- -#if defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) -# if defined(__PIC__) && defined(__i386__) - // Case for x86 with PIC -# define EIGEN_CPUID(abcd,func,id) \ - __asm__ __volatile__ ("xchgl %%ebx, %%esi;cpuid; xchgl %%ebx,%%esi": "=a" (abcd[0]), "=S" (abcd[1]), "=c" (abcd[2]), "=d" (abcd[3]) : "a" (func), "c" (id)); -# else - // Case for x86_64 or x86 w/o PIC -# define EIGEN_CPUID(abcd,func,id) \ - __asm__ __volatile__ ("cpuid": "=a" (abcd[0]), "=b" (abcd[1]), "=c" (abcd[2]), "=d" (abcd[3]) : "a" (func), "c" (id) ); -# endif -#elif defined(_MSC_VER) -# if (_MSC_VER > 1500) -# define EIGEN_CPUID(abcd,func,id) __cpuidex((int*)abcd,func,id) +#if !defined(EIGEN_NO_CPUID) +# if defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) +# if defined(__PIC__) && defined(__i386__) + // Case for x86 with PIC +# define EIGEN_CPUID(abcd,func,id) \ + __asm__ __volatile__ ("xchgl %%ebx, %%esi;cpuid; xchgl %%ebx,%%esi": "=a" (abcd[0]), "=S" (abcd[1]), "=c" (abcd[2]), "=d" (abcd[3]) : "a" (func), "c" (id)); +# else + // Case for x86_64 or x86 w/o PIC +# define EIGEN_CPUID(abcd,func,id) \ + __asm__ __volatile__ ("cpuid": "=a" (abcd[0]), "=b" (abcd[1]), "=c" (abcd[2]), "=d" (abcd[3]) : "a" (func), "c" (id) ); +# endif +# elif defined(_MSC_VER) +# if (_MSC_VER > 1500) +# define EIGEN_CPUID(abcd,func,id) __cpuidex((int*)abcd,func,id) +# endif # endif #endif @@ -742,7 +757,7 @@ namespace internal { inline bool cpuid_is_vendor(int abcd[4], const char* vendor) { - return abcd[1]==((int*)(vendor))[0] && abcd[3]==((int*)(vendor))[1] && abcd[2]==((int*)(vendor))[2]; + return abcd[1]==(reinterpret_cast(vendor))[0] && abcd[3]==(reinterpret_cast(vendor))[1] && abcd[2]==(reinterpret_cast(vendor))[2]; } inline void queryCacheSizes_intel_direct(int& l1, int& l2, int& l3) @@ -932,4 +947,6 @@ inline int queryTopLevelCacheSize() } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_MEMORY_H diff --git a/extern/Eigen3/Eigen/src/Core/util/Meta.h b/extern/Eigen3/Eigen/src/Core/util/Meta.h index 4518261efef..a5f31164d15 100644 --- a/extern/Eigen3/Eigen/src/Core/util/Meta.h +++ b/extern/Eigen3/Eigen/src/Core/util/Meta.h @@ -4,28 +4,15 @@ // Copyright (C) 2008-2009 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_META_H #define EIGEN_META_H +namespace Eigen { + namespace internal { /** \internal @@ -80,8 +67,6 @@ template<> struct is_arithmetic { enum { value = true }; }; template<> struct is_arithmetic { enum { value = true }; }; template<> struct is_arithmetic { enum { value = true }; }; template<> struct is_arithmetic { enum { value = true }; }; -template<> struct is_arithmetic { enum { value = true }; }; -template<> struct is_arithmetic { enum { value = true }; }; template struct add_const { typedef const T type; }; template struct add_const { typedef T& type; }; @@ -103,6 +88,21 @@ template struct enable_if; template struct enable_if { typedef T type; }; + + +/** \internal + * A base class do disable default copy ctor and copy assignement operator. + */ +class noncopyable +{ + noncopyable(const noncopyable&); + const noncopyable& operator=(const noncopyable&); +protected: + noncopyable() {} + ~noncopyable() {} +}; + + /** \internal * Convenient struct to get the result type of a unary or binary functor. * @@ -226,4 +226,6 @@ template struct is_diagonal > } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_META_H diff --git a/extern/Eigen3/Eigen/src/Core/util/NonMPL2.h b/extern/Eigen3/Eigen/src/Core/util/NonMPL2.h new file mode 100644 index 00000000000..1af67cf18c7 --- /dev/null +++ b/extern/Eigen3/Eigen/src/Core/util/NonMPL2.h @@ -0,0 +1,3 @@ +#ifdef EIGEN_MPL2_ONLY +#error Including non-MPL2 code in EIGEN_MPL2_ONLY mode +#endif diff --git a/extern/Eigen3/Eigen/src/Core/util/StaticAssert.h b/extern/Eigen3/Eigen/src/Core/util/StaticAssert.h index 99c7c9972f0..b46a75b3783 100644 --- a/extern/Eigen3/Eigen/src/Core/util/StaticAssert.h +++ b/extern/Eigen3/Eigen/src/Core/util/StaticAssert.h @@ -4,24 +4,9 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_STATIC_ASSERT_H #define EIGEN_STATIC_ASSERT_H @@ -48,6 +33,8 @@ #else // not CXX0X + namespace Eigen { + namespace internal { template @@ -70,6 +57,7 @@ YOU_CALLED_A_DYNAMIC_SIZE_METHOD_ON_A_FIXED_SIZE_MATRIX_OR_VECTOR, UNALIGNED_LOAD_AND_STORE_OPERATIONS_UNIMPLEMENTED_ON_ALTIVEC, THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES, + FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED, NUMERIC_TYPE_MUST_BE_REAL, COEFFICIENT_WRITE_ACCESS_TO_SELFADJOINT_NOT_SUPPORTED, WRITING_TO_TRIANGULAR_PART_WITH_UNIT_DIAGONAL_IS_NOT_SUPPORTED, @@ -95,12 +83,20 @@ YOU_PERFORMED_AN_INVALID_TRANSFORMATION_CONVERSION, THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY, YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT, - THIS_METHOD_IS_ONLY_FOR_1x1_EXPRESSIONS + THIS_METHOD_IS_ONLY_FOR_1x1_EXPRESSIONS, + THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL, + THIS_METHOD_IS_ONLY_FOR_ARRAYS_NOT_MATRICES, + YOU_PASSED_A_ROW_VECTOR_BUT_A_COLUMN_VECTOR_WAS_EXPECTED, + YOU_PASSED_A_COLUMN_VECTOR_BUT_A_ROW_VECTOR_WAS_EXPECTED, + THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE, + THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH }; }; } // end namespace internal + } // end namespace Eigen + // Specialized implementation for MSVC to avoid "conditional // expression is constant" warnings. This implementation doesn't // appear to work under GCC, hence the multiple implementations. @@ -195,4 +191,15 @@ EIGEN_STATIC_ASSERT(internal::is_lvalue::value, \ THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY) +#define EIGEN_STATIC_ASSERT_ARRAYXPR(Derived) \ + EIGEN_STATIC_ASSERT((internal::is_same::XprKind, ArrayXpr>::value), \ + THIS_METHOD_IS_ONLY_FOR_ARRAYS_NOT_MATRICES) + +#define EIGEN_STATIC_ASSERT_SAME_XPR_KIND(Derived1, Derived2) \ + EIGEN_STATIC_ASSERT((internal::is_same::XprKind, \ + typename internal::traits::XprKind \ + >::value), \ + YOU_CANNOT_MIX_ARRAYS_AND_MATRICES) + + #endif // EIGEN_STATIC_ASSERT_H diff --git a/extern/Eigen3/Eigen/src/Core/util/XprHelper.h b/extern/Eigen3/Eigen/src/Core/util/XprHelper.h index c2078f13786..2a65c7cbfa4 100644 --- a/extern/Eigen3/Eigen/src/Core/util/XprHelper.h +++ b/extern/Eigen3/Eigen/src/Core/util/XprHelper.h @@ -4,24 +4,9 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_XPRHELPER_H #define EIGEN_XPRHELPER_H @@ -37,6 +22,8 @@ #define EIGEN_EMPTY_STRUCT_CTOR(X) #endif +namespace Eigen { + typedef EIGEN_DEFAULT_DENSE_INDEX_TYPE DenseIndex; namespace internal { @@ -260,30 +247,27 @@ template struct plain_matrix_type_row_major // we should be able to get rid of this one too template struct must_nest_by_value { enum { ret = false }; }; -template -struct is_reference -{ - enum { ret = false }; -}; - -template -struct is_reference -{ - enum { ret = true }; -}; - -/** -* \internal The reference selector for template expressions. The idea is that we don't -* need to use references for expressions since they are light weight proxy -* objects which should generate no copying overhead. -**/ +/** \internal The reference selector for template expressions. The idea is that we don't + * need to use references for expressions since they are light weight proxy + * objects which should generate no copying overhead. */ template struct ref_selector { typedef typename conditional< bool(traits::Flags & NestByRefBit), T const&, - T + const T + >::type type; +}; + +/** \internal Adds the const qualifier on the value-type of T2 if and only if T1 is a const type */ +template +struct transfer_constness +{ + typedef typename conditional< + bool(internal::is_const::value), + typename internal::add_const_on_value_type::type, + T2 >::type type; }; @@ -297,6 +281,8 @@ struct ref_selector * \param T the type of the expression being nested * \param n the number of coefficient accesses in the nested expression for each coefficient access in the bigger expression. * + * Note that if no evaluation occur, then the constness of T is preserved. + * * Example. Suppose that a, b, and c are of type Matrix3d. The user forms the expression a*(b+c). * b+c is an expression "sum of matrices", which we will denote by S. In order to determine how to nest it, * the Product expression uses: nested::ret, which turns out to be Matrix3d because the internal logic of @@ -456,4 +442,6 @@ struct is_lvalue } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_XPRHELPER_H diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/Block.h b/extern/Eigen3/Eigen/src/Eigen2Support/Block.h index bc28051e017..604456f40e7 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/Block.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/Block.h @@ -4,28 +4,15 @@ // Copyright (C) 2008-2009 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_BLOCK2_H #define EIGEN_BLOCK2_H +namespace Eigen { + /** \returns a dynamic-size expression of a corner of *this. * * \param type the type of corner. Can be \a Eigen::TopLeft, \a Eigen::TopRight, @@ -134,4 +121,6 @@ DenseBase::corner(CornerType type) const } } +} // end namespace Eigen + #endif // EIGEN_BLOCK2_H diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/Cwise.h b/extern/Eigen3/Eigen/src/Eigen2Support/Cwise.h index 2dc83b6a7dd..d95009b6e29 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/Cwise.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/Cwise.h @@ -4,28 +4,15 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CWISE_H #define EIGEN_CWISE_H +namespace Eigen { + /** \internal * convenient macro to defined the return type of a cwise binary operation */ #define EIGEN_CWISE_BINOP_RETURN_TYPE(OP) \ @@ -200,4 +187,6 @@ inline Cwise MatrixBase::cwise() return derived(); } +} // end namespace Eigen + #endif // EIGEN_CWISE_H diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/CwiseOperators.h b/extern/Eigen3/Eigen/src/Eigen2Support/CwiseOperators.h index 9c28559c329..482f3064856 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/CwiseOperators.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/CwiseOperators.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ARRAY_CWISE_OPERATORS_H #define EIGEN_ARRAY_CWISE_OPERATORS_H +namespace Eigen { + /*************************************************************************** * The following functions were defined in Core ***************************************************************************/ @@ -306,4 +293,6 @@ inline ExpressionType& Cwise::operator-=(const Scalar& scalar) return m_matrix.const_cast_derived() = *this - scalar; } +} // end namespace Eigen + #endif // EIGEN_ARRAY_CWISE_OPERATORS_H diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/AlignedBox.h b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/AlignedBox.h index 78df29d408a..5c928e8fc2d 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/AlignedBox.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/AlignedBox.h @@ -3,27 +3,14 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // no include guard, we'll include this twice from All.h from Eigen2Support, and it's internal anyway +namespace Eigen { + /** \geometry_module \ingroup Geometry_Module * \nonstableyet * @@ -63,7 +50,7 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim== ~AlignedBox() {} /** \returns the dimension in which the box holds */ - inline int dim() const { return AmbientDimAtCompileTime==Dynamic ? m_min.size()-1 : int(AmbientDimAtCompileTime); } + inline int dim() const { return AmbientDimAtCompileTime==Dynamic ? m_min.size()-1 : AmbientDimAtCompileTime; } /** \returns true if the box is null, i.e, empty. */ inline bool isNull() const { return (m_min.cwise() > m_max).any(); } @@ -157,14 +144,16 @@ protected: template inline Scalar AlignedBox::squaredExteriorDistance(const VectorType& p) const { - Scalar dist2 = 0.; + Scalar dist2(0); Scalar aux; for (int k=0; k // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // no include guard, we'll include this twice from All.h from Eigen2Support, and it's internal anyway +namespace Eigen { /** \geometry_module \ingroup Geometry_Module * @@ -224,3 +210,5 @@ AngleAxis::toRotationMatrix(void) const return res; } + +} // end namespace Eigen diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Hyperplane.h b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Hyperplane.h index 81c4f55b173..19cc1bfd883 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Hyperplane.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Hyperplane.h @@ -4,27 +4,14 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // no include guard, we'll include this twice from All.h from Eigen2Support, and it's internal anyway +namespace Eigen { + /** \geometry_module \ingroup Geometry_Module * * \class Hyperplane @@ -263,3 +250,5 @@ protected: Coefficients m_coeffs; }; + +} // end namespace Eigen diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/ParametrizedLine.h b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/ParametrizedLine.h index 411c4b57079..6e4a168a8cd 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/ParametrizedLine.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/ParametrizedLine.h @@ -4,27 +4,13 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // no include guard, we'll include this twice from All.h from Eigen2Support, and it's internal anyway +namespace Eigen { /** \geometry_module \ingroup Geometry_Module * @@ -151,3 +137,5 @@ inline _Scalar ParametrizedLine<_Scalar, _AmbientDim>::intersection(const Hyperp return -(hyperplane.offset()+origin().eigen2_dot(hyperplane.normal())) /(direction().eigen2_dot(hyperplane.normal())); } + +} // end namespace Eigen diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Quaternion.h b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Quaternion.h index a75fa42aeac..ec87da054d6 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Quaternion.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Quaternion.h @@ -3,27 +3,14 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // no include guard, we'll include this twice from All.h from Eigen2Support, and it's internal anyway +namespace Eigen { + template @@ -143,7 +130,7 @@ public: /** \returns a quaternion representing an identity rotation * \sa MatrixBase::Identity() */ - inline static Quaternion Identity() { return Quaternion(1, 0, 0, 0); } + static inline Quaternion Identity() { return Quaternion(1, 0, 0, 0); } /** \sa Quaternion::Identity(), MatrixBase::setIdentity() */ @@ -314,9 +301,9 @@ Quaternion::toRotationMatrix(void) const // it has to be inlined, and so the return by value is not an issue Matrix3 res; - const Scalar tx = 2*this->x(); - const Scalar ty = 2*this->y(); - const Scalar tz = 2*this->z(); + const Scalar tx = Scalar(2)*this->x(); + const Scalar ty = Scalar(2)*this->y(); + const Scalar tz = Scalar(2)*this->z(); const Scalar twx = tx*this->w(); const Scalar twy = ty*this->w(); const Scalar twz = tz*this->w(); @@ -327,15 +314,15 @@ Quaternion::toRotationMatrix(void) const const Scalar tyz = tz*this->y(); const Scalar tzz = tz*this->z(); - res.coeffRef(0,0) = 1-(tyy+tzz); + res.coeffRef(0,0) = Scalar(1)-(tyy+tzz); res.coeffRef(0,1) = txy-twz; res.coeffRef(0,2) = txz+twy; res.coeffRef(1,0) = txy+twz; - res.coeffRef(1,1) = 1-(txx+tzz); + res.coeffRef(1,1) = Scalar(1)-(txx+tzz); res.coeffRef(1,2) = tyz-twx; res.coeffRef(2,0) = txz-twy; res.coeffRef(2,1) = tyz+twx; - res.coeffRef(2,2) = 1-(txx+tyy); + res.coeffRef(2,2) = Scalar(1)-(txx+tyy); return res; } @@ -460,7 +447,7 @@ template struct ei_quaternion_assign_impl { typedef typename Other::Scalar Scalar; - inline static void run(Quaternion& q, const Other& mat) + static inline void run(Quaternion& q, const Other& mat) { // This algorithm comes from "Quaternion Calculus and Fast Animation", // Ken Shoemake, 1987 SIGGRAPH course notes @@ -499,8 +486,10 @@ template struct ei_quaternion_assign_impl { typedef typename Other::Scalar Scalar; - inline static void run(Quaternion& q, const Other& vec) + static inline void run(Quaternion& q, const Other& vec) { q.coeffs() = vec; } }; + +} // end namespace Eigen diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Rotation2D.h b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Rotation2D.h index ee7c80e7eaa..3e02b7a4fd1 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Rotation2D.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Rotation2D.h @@ -3,27 +3,13 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // no include guard, we'll include this twice from All.h from Eigen2Support, and it's internal anyway +namespace Eigen { /** \geometry_module \ingroup Geometry_Module * @@ -155,3 +141,5 @@ Rotation2D::toRotationMatrix(void) const Scalar cosA = ei_cos(m_angle); return (Matrix2() << cosA, -sinA, sinA, cosA).finished(); } + +} // end namespace Eigen diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/RotationBase.h b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/RotationBase.h index 2f494f198bd..78ad73b60ad 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/RotationBase.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/RotationBase.h @@ -3,27 +3,14 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // no include guard, we'll include this twice from All.h from Eigen2Support, and it's internal anyway +namespace Eigen { + // this file aims to contains the various representations of rotation/orientation // in 2D and 3D space excepted Matrix and Quaternion. @@ -113,22 +100,24 @@ Matrix<_Scalar, _Rows, _Cols, _Storage, _MaxRows, _MaxCols> * \sa class Transform, class Rotation2D, class Quaternion, class AngleAxis */ template -inline static Matrix ei_toRotationMatrix(const Scalar& s) +static inline Matrix ei_toRotationMatrix(const Scalar& s) { EIGEN_STATIC_ASSERT(Dim==2,YOU_MADE_A_PROGRAMMING_MISTAKE) return Rotation2D(s).toRotationMatrix(); } template -inline static Matrix ei_toRotationMatrix(const RotationBase& r) +static inline Matrix ei_toRotationMatrix(const RotationBase& r) { return r.toRotationMatrix(); } template -inline static const MatrixBase& ei_toRotationMatrix(const MatrixBase& mat) +static inline const MatrixBase& ei_toRotationMatrix(const MatrixBase& mat) { EIGEN_STATIC_ASSERT(OtherDerived::RowsAtCompileTime==Dim && OtherDerived::ColsAtCompileTime==Dim, YOU_MADE_A_PROGRAMMING_MISTAKE) return mat; } + +} // end namespace Eigen diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Scaling.h b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Scaling.h index 108e6d7d58f..a07c1c7c762 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Scaling.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Scaling.h @@ -3,27 +3,13 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // no include guard, we'll include this twice from All.h from Eigen2Support, and it's internal anyway +namespace Eigen { /** \geometry_module \ingroup Geometry_Module * @@ -177,3 +163,5 @@ Scaling::operator* (const TransformType& t) const res.prescale(m_coeffs); return res; } + +} // end namespace Eigen diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Transform.h b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Transform.h index 88956c86c73..dceb8020383 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Transform.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Transform.h @@ -4,27 +4,13 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2009 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // no include guard, we'll include this twice from All.h from Eigen2Support, and it's internal anyway +namespace Eigen { // Note that we have to pass Dim and HDim because it is not allowed to use a template // parameter to define a template specialization. To be more precise, in the following @@ -796,3 +782,5 @@ struct ei_transform_product_impl { return ((tr.linear() * other) + tr.translation()) * (Scalar(1) / ( (tr.matrix().template block<1,Dim>(Dim,0) * other).coeff(0) + tr.matrix().coeff(Dim,Dim))); } }; + +} // end namespace Eigen diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Translation.h b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Translation.h index e651e310212..0fb9a9f9a5a 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Translation.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Translation.h @@ -3,27 +3,13 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // no include guard, we'll include this twice from All.h from Eigen2Support, and it's internal anyway +namespace Eigen { /** \geometry_module \ingroup Geometry_Module * @@ -194,3 +180,5 @@ Translation::operator* (const TransformType& t) const res.pretranslate(m_coeffs); return res; } + +} // end namespace Eigen diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/LU.h b/extern/Eigen3/Eigen/src/Eigen2Support/LU.h index c23c11baa72..49f19ad76e3 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/LU.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/LU.h @@ -3,28 +3,15 @@ // // Copyright (C) 2011 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN2_LU_H #define EIGEN2_LU_H +namespace Eigen { + template class LU : public FullPivLU { @@ -57,7 +44,6 @@ class LU : public FullPivLU > ImageResultType; typedef FullPivLU Base; - LU() : Base() {} template explicit LU(const T& t) : Base(t), m_originalMatrix(t) {} @@ -129,5 +115,6 @@ MatrixBase::eigen2_lu() const } #endif +} // end namespace Eigen #endif // EIGEN2_LU_H diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/Lazy.h b/extern/Eigen3/Eigen/src/Eigen2Support/Lazy.h index c4288ede2ef..593fc78e6de 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/Lazy.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/Lazy.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_LAZY_H #define EIGEN_LAZY_H +namespace Eigen { + /** \deprecated it is only used by lazy() which is deprecated * * \returns an expression of *this with added flags @@ -79,4 +66,6 @@ Derived& MatrixBase::operator-=(const Flagged // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN2_LEASTSQUARES_H #define EIGEN2_LEASTSQUARES_H +namespace Eigen { + /** \ingroup LeastSquares_Module * * \leastsquares_module @@ -178,5 +165,6 @@ void fitHyperplane(int numPoints, result->offset() = - (result->normal().cwise()* mean).sum(); } +} // end namespace Eigen #endif // EIGEN2_LEASTSQUARES_H diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/Macros.h b/extern/Eigen3/Eigen/src/Eigen2Support/Macros.h index 77e85a41e3d..351c32afb60 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/Macros.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/Macros.h @@ -3,24 +3,9 @@ // // Copyright (C) 2011 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN2_MACROS_H #define EIGEN2_MACROS_H diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/MathFunctions.h b/extern/Eigen3/Eigen/src/Eigen2Support/MathFunctions.h index caa44e63f32..3a8a9ca8146 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/MathFunctions.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/MathFunctions.h @@ -3,28 +3,15 @@ // // Copyright (C) 2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN2_MATH_FUNCTIONS_H #define EIGEN2_MATH_FUNCTIONS_H +namespace Eigen { + template inline typename NumTraits::Real ei_real(const T& x) { return internal::real(x); } template inline typename NumTraits::Real ei_imag(const T& x) { return internal::imag(x); } template inline T ei_conj(const T& x) { return internal::conj(x); } @@ -65,4 +52,6 @@ inline bool ei_isApproxOrLessThan(const Scalar& x, const Scalar& y, return internal::isApproxOrLessThan(x, y, precision); } +} // end namespace Eigen + #endif // EIGEN2_MATH_FUNCTIONS_H diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/Memory.h b/extern/Eigen3/Eigen/src/Eigen2Support/Memory.h index 0283475419e..f86372b6b56 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/Memory.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/Memory.h @@ -3,28 +3,15 @@ // // Copyright (C) 2011 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN2_MEMORY_H #define EIGEN2_MEMORY_H +namespace Eigen { + inline void* ei_aligned_malloc(size_t size) { return internal::aligned_malloc(size); } inline void ei_aligned_free(void *ptr) { internal::aligned_free(ptr); } inline void* ei_aligned_realloc(void *ptr, size_t new_size, size_t old_size) { return internal::aligned_realloc(ptr, new_size, old_size); } @@ -53,6 +40,6 @@ template inline void ei_aligned_delete(T *ptr, size_t size) return internal::aligned_delete(ptr, size); } - +} // end namespace Eigen #endif // EIGEN2_MACROS_H diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/Meta.h b/extern/Eigen3/Eigen/src/Eigen2Support/Meta.h index 6e500b79a2e..fa37cfc961e 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/Meta.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/Meta.h @@ -3,28 +3,15 @@ // // Copyright (C) 2011 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN2_META_H #define EIGEN2_META_H +namespace Eigen { + template struct ei_traits : internal::traits {}; @@ -83,4 +70,6 @@ class ei_meta_sqrt template class ei_meta_sqrt { public: enum { ret = (SupX*SupX <= Y) ? SupX : InfX }; }; +} // end namespace Eigen + #endif // EIGEN2_META_H diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/Minor.h b/extern/Eigen3/Eigen/src/Eigen2Support/Minor.h index eda91cc32be..4cded5734fa 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/Minor.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/Minor.h @@ -3,28 +3,15 @@ // // Copyright (C) 2006-2009 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MINOR_H #define EIGEN_MINOR_H +namespace Eigen { + /** * \class Minor * @@ -125,4 +112,6 @@ MatrixBase::minor(Index row, Index col) const return Minor(derived(), row, col); } +} // end namespace Eigen + #endif // EIGEN_MINOR_H diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/QR.h b/extern/Eigen3/Eigen/src/Eigen2Support/QR.h index 64f5d5ccb30..2042c98510a 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/QR.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/QR.h @@ -4,28 +4,15 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2011 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN2_QR_H #define EIGEN2_QR_H +namespace Eigen { + template class QR : public HouseholderQR { @@ -75,5 +62,6 @@ MatrixBase::qr() const return QR(eval()); } +} // end namespace Eigen #endif // EIGEN2_QR_H diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/SVD.h b/extern/Eigen3/Eigen/src/Eigen2Support/SVD.h index 16b4b488f0c..3d2eeb44586 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/SVD.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/SVD.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN2_SVD_H #define EIGEN2_SVD_H +namespace Eigen { + /** \ingroup SVD_Module * \nonstableyet * @@ -390,7 +377,7 @@ void SVD::compute(const MatrixType& matrix) Scalar ek = e[k]/scale; Scalar b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/Scalar(2); Scalar c = (sp*epm1)*(sp*epm1); - Scalar shift = 0.0; + Scalar shift(0); if ((b != 0.0) || (c != 0.0)) { shift = ei_sqrt(b*b + c); @@ -646,4 +633,6 @@ MatrixBase::svd() const return SVD(derived()); } +} // end namespace Eigen + #endif // EIGEN2_SVD_H diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/TriangularSolver.h b/extern/Eigen3/Eigen/src/Eigen2Support/TriangularSolver.h index e94e47a5093..ebbeb3b4958 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/TriangularSolver.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/TriangularSolver.h @@ -3,28 +3,15 @@ // // Copyright (C) 2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_TRIANGULAR_SOLVER2_H #define EIGEN_TRIANGULAR_SOLVER2_H +namespace Eigen { + const unsigned int UnitDiagBit = UnitDiag; const unsigned int SelfAdjointBit = SelfAdjoint; const unsigned int UpperTriangularBit = Upper; @@ -49,5 +36,7 @@ void Flagged::solveTriangularInPlace(const MatrixB { m_matrix.template triangularView().solveInPlace(other.derived()); } + +} // end namespace Eigen #endif // EIGEN_TRIANGULAR_SOLVER2_H diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/VectorBlock.h b/extern/Eigen3/Eigen/src/Eigen2Support/VectorBlock.h index 010031d1971..71a8080a9fc 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/VectorBlock.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/VectorBlock.h @@ -4,28 +4,15 @@ // Copyright (C) 2008-2009 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN2_VECTORBLOCK_H #define EIGEN2_VECTORBLOCK_H +namespace Eigen { + /** \deprecated use DenseMase::head(Index) */ template inline VectorBlock @@ -102,4 +89,6 @@ MatrixBase::end() const return VectorBlock(derived(), size() - Size); } +} // end namespace Eigen + #endif // EIGEN2_VECTORBLOCK_H diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h b/extern/Eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h index 57e00227d72..c4b8a308cee 100644 --- a/extern/Eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h +++ b/extern/Eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h @@ -5,31 +5,17 @@ // Copyright (C) 2009 Gael Guennebaud // Copyright (C) 2010 Jitse Niesen // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_COMPLEX_EIGEN_SOLVER_H #define EIGEN_COMPLEX_EIGEN_SOLVER_H -#include "./EigenvaluesCommon.h" #include "./ComplexSchur.h" +namespace Eigen { + /** \eigenvalues_module \ingroup Eigenvalues_Module * * @@ -328,5 +314,6 @@ void ComplexEigenSolver::sortEigenvalues(bool computeEigenvectors) } } +} // end namespace Eigen #endif // EIGEN_COMPLEX_EIGEN_SOLVER_H diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/ComplexSchur.h b/extern/Eigen3/Eigen/src/Eigenvalues/ComplexSchur.h index ec93af2e58a..16a9a03d219 100644 --- a/extern/Eigen3/Eigen/src/Eigenvalues/ComplexSchur.h +++ b/extern/Eigen3/Eigen/src/Eigenvalues/ComplexSchur.h @@ -5,31 +5,17 @@ // Copyright (C) 2009 Gael Guennebaud // Copyright (C) 2010 Jitse Niesen // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_COMPLEX_SCHUR_H #define EIGEN_COMPLEX_SCHUR_H -#include "./EigenvaluesCommon.h" #include "./HessenbergDecomposition.h" +namespace Eigen { + namespace internal { template struct complex_schur_reduce_to_hessenberg; } @@ -227,46 +213,6 @@ template class ComplexSchur friend struct internal::complex_schur_reduce_to_hessenberg::IsComplex>; }; -namespace internal { - -/** Computes the principal value of the square root of the complex \a z. */ -template -std::complex sqrt(const std::complex &z) -{ - RealScalar t, tre, tim; - - t = abs(z); - - if (abs(real(z)) <= abs(imag(z))) - { - // No cancellation in these formulas - tre = sqrt(RealScalar(0.5)*(t + real(z))); - tim = sqrt(RealScalar(0.5)*(t - real(z))); - } - else - { - // Stable computation of the above formulas - if (z.real() > RealScalar(0)) - { - tre = t + z.real(); - tim = abs(imag(z))*sqrt(RealScalar(0.5)/tre); - tre = sqrt(RealScalar(0.5)*tre); - } - else - { - tim = t - z.real(); - tre = abs(imag(z))*sqrt(RealScalar(0.5)/tim); - tim = sqrt(RealScalar(0.5)*tim); - } - } - if(z.imag() < RealScalar(0)) - tim = -tim; - - return (std::complex(tre,tim)); -} -} // end namespace internal - - /** If m_matT(i+1,i) is neglegible in floating point arithmetic * compared to m_matT(i,i) and m_matT(j,j), then set it to zero and * return true, else return false. */ @@ -302,7 +248,7 @@ typename ComplexSchur::ComplexScalar ComplexSchur::compu ComplexScalar b = t.coeff(0,1) * t.coeff(1,0); ComplexScalar c = t.coeff(0,0) - t.coeff(1,1); - ComplexScalar disc = internal::sqrt(c*c + RealScalar(4)*b); + ComplexScalar disc = sqrt(c*c + RealScalar(4)*b); ComplexScalar det = t.coeff(0,0) * t.coeff(1,1) - b; ComplexScalar trace = t.coeff(0,0) + t.coeff(1,1); ComplexScalar eival1 = (trace + disc) / RealScalar(2); @@ -406,7 +352,7 @@ void ComplexSchur::reduceToTriangularForm(bool computeU) // if we spent too many iterations on the current element, we give up iter++; - if(iter > m_maxIterations) break; + if(iter > m_maxIterations * m_matT.cols()) break; // find il, the top row of the active submatrix il = iu-1; @@ -436,7 +382,7 @@ void ComplexSchur::reduceToTriangularForm(bool computeU) } } - if(iter <= m_maxIterations) + if(iter <= m_maxIterations * m_matT.cols()) m_info = Success; else m_info = NoConvergence; @@ -445,4 +391,6 @@ void ComplexSchur::reduceToTriangularForm(bool computeU) m_matUisUptodate = computeU; } +} // end namespace Eigen + #endif // EIGEN_COMPLEX_SCHUR_H diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/ComplexSchur_MKL.h b/extern/Eigen3/Eigen/src/Eigenvalues/ComplexSchur_MKL.h new file mode 100644 index 00000000000..aa18e696352 --- /dev/null +++ b/extern/Eigen3/Eigen/src/Eigenvalues/ComplexSchur_MKL.h @@ -0,0 +1,94 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * Complex Schur needed to complex unsymmetrical eigenvalues/eigenvectors. + ******************************************************************************** +*/ + +#ifndef EIGEN_COMPLEX_SCHUR_MKL_H +#define EIGEN_COMPLEX_SCHUR_MKL_H + +#include "Eigen/src/Core/util/MKL_support.h" + +namespace Eigen { + +/** \internal Specialization for the data types supported by MKL */ + +#define EIGEN_MKL_SCHUR_COMPLEX(EIGTYPE, MKLTYPE, MKLPREFIX, MKLPREFIX_U, EIGCOLROW, MKLCOLROW) \ +template<> inline\ +ComplexSchur >& \ +ComplexSchur >::compute(const Matrix& matrix, bool computeU) \ +{ \ + typedef Matrix MatrixType; \ + typedef MatrixType::Scalar Scalar; \ + typedef MatrixType::RealScalar RealScalar; \ + typedef std::complex ComplexScalar; \ +\ + assert(matrix.cols() == matrix.rows()); \ +\ + m_matUisUptodate = false; \ + if(matrix.cols() == 1) \ + { \ + m_matT = matrix.cast(); \ + if(computeU) m_matU = ComplexMatrixType::Identity(1,1); \ + m_info = Success; \ + m_isInitialized = true; \ + m_matUisUptodate = computeU; \ + return *this; \ + } \ + lapack_int n = matrix.cols(), sdim, info; \ + lapack_int lda = matrix.outerStride(); \ + lapack_int matrix_order = MKLCOLROW; \ + char jobvs, sort='N'; \ + LAPACK_##MKLPREFIX_U##_SELECT1 select = 0; \ + jobvs = (computeU) ? 'V' : 'N'; \ + m_matU.resize(n, n); \ + lapack_int ldvs = m_matU.outerStride(); \ + m_matT = matrix; \ + Matrix w; \ + w.resize(n, 1);\ + info = LAPACKE_##MKLPREFIX##gees( matrix_order, jobvs, sort, select, n, (MKLTYPE*)m_matT.data(), lda, &sdim, (MKLTYPE*)w.data(), (MKLTYPE*)m_matU.data(), ldvs ); \ + if(info == 0) \ + m_info = Success; \ + else \ + m_info = NoConvergence; \ +\ + m_isInitialized = true; \ + m_matUisUptodate = computeU; \ + return *this; \ +\ +} + +EIGEN_MKL_SCHUR_COMPLEX(dcomplex, MKL_Complex16, z, Z, ColMajor, LAPACK_COL_MAJOR) +EIGEN_MKL_SCHUR_COMPLEX(scomplex, MKL_Complex8, c, C, ColMajor, LAPACK_COL_MAJOR) +EIGEN_MKL_SCHUR_COMPLEX(dcomplex, MKL_Complex16, z, Z, RowMajor, LAPACK_ROW_MAJOR) +EIGEN_MKL_SCHUR_COMPLEX(scomplex, MKL_Complex8, c, C, RowMajor, LAPACK_ROW_MAJOR) + +} // end namespace Eigen + +#endif // EIGEN_COMPLEX_SCHUR_MKL_H diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/EigenSolver.h b/extern/Eigen3/Eigen/src/Eigenvalues/EigenSolver.h index f57353c065f..c16ff2b74e2 100644 --- a/extern/Eigen3/Eigen/src/Eigenvalues/EigenSolver.h +++ b/extern/Eigen3/Eigen/src/Eigenvalues/EigenSolver.h @@ -4,31 +4,17 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2010 Jitse Niesen // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_EIGENSOLVER_H #define EIGEN_EIGENSOLVER_H -#include "./EigenvaluesCommon.h" #include "./RealSchur.h" +namespace Eigen { + /** \eigenvalues_module \ingroup Eigenvalues_Module * * @@ -432,7 +418,7 @@ void EigenSolver::doComputeEigenvectors() const Scalar eps = NumTraits::epsilon(); // inefficient! this is already computed in RealSchur - Scalar norm = 0.0; + Scalar norm(0); for (Index j = 0; j < size; ++j) { norm += m_matT.row(j).segment((std::max)(j-1,Index(0)), size-(std::max)(j-1,Index(0))).cwiseAbs().sum(); @@ -452,7 +438,7 @@ void EigenSolver::doComputeEigenvectors() // Scalar vector if (q == Scalar(0)) { - Scalar lastr=0, lastw=0; + Scalar lastr(0), lastw(0); Index l = n; m_matT.coeffRef(n,n) = 1.0; @@ -498,7 +484,7 @@ void EigenSolver::doComputeEigenvectors() } else if (q < Scalar(0) && n > 0) // Complex vector { - Scalar lastra=0, lastsa=0, lastw=0; + Scalar lastra(0), lastsa(0), lastw(0); Index l = n-1; // Last vector component imaginary so matrix is triangular @@ -588,4 +574,6 @@ void EigenSolver::doComputeEigenvectors() } } +} // end namespace Eigen + #endif // EIGEN_EIGENSOLVER_H diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/EigenvaluesCommon.h b/extern/Eigen3/Eigen/src/Eigenvalues/EigenvaluesCommon.h deleted file mode 100644 index 749bea79500..00000000000 --- a/extern/Eigen3/Eigen/src/Eigenvalues/EigenvaluesCommon.h +++ /dev/null @@ -1,31 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2010 Jitse Niesen -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_EIGENVALUES_COMMON_H -#define EIGEN_EIGENVALUES_COMMON_H - - - -#endif // EIGEN_EIGENVALUES_COMMON_H - diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h b/extern/Eigen3/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h index 980af14ce71..07bf1ea0956 100644 --- a/extern/Eigen3/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h +++ b/extern/Eigen3/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h @@ -4,31 +4,17 @@ // Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2010 Jitse Niesen // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_GENERALIZEDSELFADJOINTEIGENSOLVER_H #define EIGEN_GENERALIZEDSELFADJOINTEIGENSOLVER_H -#include "./EigenvaluesCommon.h" #include "./Tridiagonalization.h" +namespace Eigen { + /** \eigenvalues_module \ingroup Eigenvalues_Module * * @@ -236,4 +222,6 @@ compute(const MatrixType& matA, const MatrixType& matB, int options) return *this; } +} // end namespace Eigen + #endif // EIGEN_GENERALIZEDSELFADJOINTEIGENSOLVER_H diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/HessenbergDecomposition.h b/extern/Eigen3/Eigen/src/Eigenvalues/HessenbergDecomposition.h index c17f155a59b..b8378b08a09 100644 --- a/extern/Eigen3/Eigen/src/Eigenvalues/HessenbergDecomposition.h +++ b/extern/Eigen3/Eigen/src/Eigenvalues/HessenbergDecomposition.h @@ -4,28 +4,15 @@ // Copyright (C) 2008-2009 Gael Guennebaud // Copyright (C) 2010 Jitse Niesen // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_HESSENBERGDECOMPOSITION_H #define EIGEN_HESSENBERGDECOMPOSITION_H +namespace Eigen { + namespace internal { template struct HessenbergDecompositionMatrixHReturnType; @@ -379,6 +366,8 @@ template struct HessenbergDecompositionMatrixHReturnType const HessenbergDecomposition& m_hess; }; -} +} // end namespace internal + +} // end namespace Eigen #endif // EIGEN_HESSENBERGDECOMPOSITION_H diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h b/extern/Eigen3/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h index 5591519fb75..6af481c75f6 100644 --- a/extern/Eigen3/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h +++ b/extern/Eigen3/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h @@ -4,28 +4,15 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2010 Jitse Niesen // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MATRIXBASEEIGENVALUES_H #define EIGEN_MATRIXBASEEIGENVALUES_H +namespace Eigen { + namespace internal { template @@ -167,4 +154,6 @@ SelfAdjointView::operatorNorm() const return eigenvalues().cwiseAbs().maxCoeff(); } +} // end namespace Eigen + #endif diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/RealSchur.h b/extern/Eigen3/Eigen/src/Eigenvalues/RealSchur.h index cc9af11c117..781692eccd3 100644 --- a/extern/Eigen3/Eigen/src/Eigenvalues/RealSchur.h +++ b/extern/Eigen3/Eigen/src/Eigenvalues/RealSchur.h @@ -4,31 +4,17 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2010 Jitse Niesen // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_REAL_SCHUR_H #define EIGEN_REAL_SCHUR_H -#include "./EigenvaluesCommon.h" #include "./HessenbergDecomposition.h" +namespace Eigen { + /** \eigenvalues_module \ingroup Eigenvalues_Module * * @@ -235,42 +221,44 @@ RealSchur& RealSchur::compute(const MatrixType& matrix, // Rows iu+1,...,end are already brought in triangular form. Index iu = m_matT.cols() - 1; Index iter = 0; // iteration count - Scalar exshift = 0.0; // sum of exceptional shifts + Scalar exshift(0); // sum of exceptional shifts Scalar norm = computeNormOfT(); - while (iu >= 0) + if(norm!=0) { - Index il = findSmallSubdiagEntry(iu, norm); - - // Check for convergence - if (il == iu) // One root found - { - m_matT.coeffRef(iu,iu) = m_matT.coeff(iu,iu) + exshift; - if (iu > 0) - m_matT.coeffRef(iu, iu-1) = Scalar(0); - iu--; - iter = 0; - } - else if (il == iu-1) // Two roots found - { - splitOffTwoRows(iu, computeU, exshift); - iu -= 2; - iter = 0; - } - else // No convergence yet + while (iu >= 0) { - // The firstHouseholderVector vector has to be initialized to something to get rid of a silly GCC warning (-O1 -Wall -DNDEBUG ) - Vector3s firstHouseholderVector(0,0,0), shiftInfo; - computeShift(iu, iter, exshift, shiftInfo); - iter = iter + 1; - if (iter > m_maxIterations) break; - Index im; - initFrancisQRStep(il, iu, shiftInfo, im, firstHouseholderVector); - performFrancisQRStep(il, im, iu, computeU, firstHouseholderVector, workspace); + Index il = findSmallSubdiagEntry(iu, norm); + + // Check for convergence + if (il == iu) // One root found + { + m_matT.coeffRef(iu,iu) = m_matT.coeff(iu,iu) + exshift; + if (iu > 0) + m_matT.coeffRef(iu, iu-1) = Scalar(0); + iu--; + iter = 0; + } + else if (il == iu-1) // Two roots found + { + splitOffTwoRows(iu, computeU, exshift); + iu -= 2; + iter = 0; + } + else // No convergence yet + { + // The firstHouseholderVector vector has to be initialized to something to get rid of a silly GCC warning (-O1 -Wall -DNDEBUG ) + Vector3s firstHouseholderVector(0,0,0), shiftInfo; + computeShift(iu, iter, exshift, shiftInfo); + iter = iter + 1; + if (iter > m_maxIterations * m_matT.cols()) break; + Index im; + initFrancisQRStep(il, iu, shiftInfo, im, firstHouseholderVector); + performFrancisQRStep(il, im, iu, computeU, firstHouseholderVector, workspace); + } } - } - - if(iter <= m_maxIterations) + } + if(iter <= m_maxIterations * m_matT.cols()) m_info = Success; else m_info = NoConvergence; @@ -288,7 +276,7 @@ inline typename MatrixType::Scalar RealSchur::computeNormOfT() // FIXME to be efficient the following would requires a triangular reduxion code // Scalar norm = m_matT.upper().cwiseAbs().sum() // + m_matT.bottomLeftCorner(size-1,size-1).diagonal().cwiseAbs().sum(); - Scalar norm = 0.0; + Scalar norm(0); for (Index j = 0; j < size; ++j) norm += m_matT.row(j).segment((std::max)(j-1,Index(0)), size-(std::max)(j-1,Index(0))).cwiseAbs().sum(); return norm; @@ -471,4 +459,6 @@ inline void RealSchur::performFrancisQRStep(Index il, Index im, Inde } } +} // end namespace Eigen + #endif // EIGEN_REAL_SCHUR_H diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/RealSchur_MKL.h b/extern/Eigen3/Eigen/src/Eigenvalues/RealSchur_MKL.h new file mode 100644 index 00000000000..960ec3c764a --- /dev/null +++ b/extern/Eigen3/Eigen/src/Eigenvalues/RealSchur_MKL.h @@ -0,0 +1,83 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * Real Schur needed to real unsymmetrical eigenvalues/eigenvectors. + ******************************************************************************** +*/ + +#ifndef EIGEN_REAL_SCHUR_MKL_H +#define EIGEN_REAL_SCHUR_MKL_H + +#include "Eigen/src/Core/util/MKL_support.h" + +namespace Eigen { + +/** \internal Specialization for the data types supported by MKL */ + +#define EIGEN_MKL_SCHUR_REAL(EIGTYPE, MKLTYPE, MKLPREFIX, MKLPREFIX_U, EIGCOLROW, MKLCOLROW) \ +template<> inline \ +RealSchur >& \ +RealSchur >::compute(const Matrix& matrix, bool computeU) \ +{ \ + typedef Matrix MatrixType; \ + typedef MatrixType::Scalar Scalar; \ + typedef MatrixType::RealScalar RealScalar; \ +\ + assert(matrix.cols() == matrix.rows()); \ +\ + lapack_int n = matrix.cols(), sdim, info; \ + lapack_int lda = matrix.outerStride(); \ + lapack_int matrix_order = MKLCOLROW; \ + char jobvs, sort='N'; \ + LAPACK_##MKLPREFIX_U##_SELECT2 select = 0; \ + jobvs = (computeU) ? 'V' : 'N'; \ + m_matU.resize(n, n); \ + lapack_int ldvs = m_matU.outerStride(); \ + m_matT = matrix; \ + Matrix wr, wi; \ + wr.resize(n, 1); wi.resize(n, 1); \ + info = LAPACKE_##MKLPREFIX##gees( matrix_order, jobvs, sort, select, n, (MKLTYPE*)m_matT.data(), lda, &sdim, (MKLTYPE*)wr.data(), (MKLTYPE*)wi.data(), (MKLTYPE*)m_matU.data(), ldvs ); \ + if(info == 0) \ + m_info = Success; \ + else \ + m_info = NoConvergence; \ +\ + m_isInitialized = true; \ + m_matUisUptodate = computeU; \ + return *this; \ +\ +} + +EIGEN_MKL_SCHUR_REAL(double, double, d, D, ColMajor, LAPACK_COL_MAJOR) +EIGEN_MKL_SCHUR_REAL(float, float, s, S, ColMajor, LAPACK_COL_MAJOR) +EIGEN_MKL_SCHUR_REAL(double, double, d, D, RowMajor, LAPACK_ROW_MAJOR) +EIGEN_MKL_SCHUR_REAL(float, float, s, S, RowMajor, LAPACK_ROW_MAJOR) + +} // end namespace Eigen + +#endif // EIGEN_REAL_SCHUR_MKL_H diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index ad107c63282..acc5576feb1 100644 --- a/extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +++ b/extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h @@ -4,34 +4,24 @@ // Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2010 Jitse Niesen // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SELFADJOINTEIGENSOLVER_H #define EIGEN_SELFADJOINTEIGENSOLVER_H -#include "./EigenvaluesCommon.h" #include "./Tridiagonalization.h" +namespace Eigen { + template class GeneralizedSelfAdjointEigenSolver; +namespace internal { +template struct direct_selfadjoint_eigenvalues; +} + /** \eigenvalues_module \ingroup Eigenvalues_Module * * @@ -86,7 +76,7 @@ template class SelfAdjointEigenSolver Options = MatrixType::Options, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime }; - + /** \brief Scalar type for matrices of type \p _MatrixType. */ typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::Index Index; @@ -98,6 +88,8 @@ template class SelfAdjointEigenSolver * complex. */ typedef typename NumTraits::Real RealScalar; + + friend struct internal::direct_selfadjoint_eigenvalues::IsComplex>; /** \brief Type for vector of eigenvalues as returned by eigenvalues(). * @@ -198,6 +190,22 @@ template class SelfAdjointEigenSolver * \sa SelfAdjointEigenSolver(const MatrixType&, int) */ SelfAdjointEigenSolver& compute(const MatrixType& matrix, int options = ComputeEigenvectors); + + /** \brief Computes eigendecomposition of given matrix using a direct algorithm + * + * This is a variant of compute(const MatrixType&, int options) which + * directly solves the underlying polynomial equation. + * + * Currently only 3x3 matrices for which the sizes are known at compile time are supported (e.g., Matrix3d). + * + * This method is usually significantly faster than the QR algorithm + * but it might also be less accurate. It is also worth noting that + * for 3x3 matrices it involves trigonometric operations which are + * not necessarily available for all scalar types. + * + * \sa compute(const MatrixType&, int options) + */ + SelfAdjointEigenSolver& computeDirect(const MatrixType& matrix, int options = ComputeEigenvectors); /** \brief Returns the eigenvectors of given matrix. * @@ -401,7 +409,7 @@ SelfAdjointEigenSolver& SelfAdjointEigenSolver // map the matrix coefficients to [-1:1] to avoid over- and underflow. RealScalar scale = matrix.cwiseAbs().maxCoeff(); - if(scale==Scalar(0)) scale = 1; + if(scale==RealScalar(0)) scale = RealScalar(1); mat = matrix / scale; m_subdiag.resize(n-1); internal::tridiagonalization_inplace(mat, diag, m_subdiag, computeEigenvectors); @@ -466,19 +474,277 @@ SelfAdjointEigenSolver& SelfAdjointEigenSolver return *this; } + +namespace internal { + +template struct direct_selfadjoint_eigenvalues +{ + static inline void run(SolverType& eig, const typename SolverType::MatrixType& A, int options) + { eig.compute(A,options); } +}; + +template struct direct_selfadjoint_eigenvalues +{ + typedef typename SolverType::MatrixType MatrixType; + typedef typename SolverType::RealVectorType VectorType; + typedef typename SolverType::Scalar Scalar; + + static inline void computeRoots(const MatrixType& m, VectorType& roots) + { + using std::sqrt; + using std::atan2; + using std::cos; + using std::sin; + const Scalar s_inv3 = Scalar(1.0)/Scalar(3.0); + const Scalar s_sqrt3 = sqrt(Scalar(3.0)); + + // The characteristic equation is x^3 - c2*x^2 + c1*x - c0 = 0. The + // eigenvalues are the roots to this equation, all guaranteed to be + // real-valued, because the matrix is symmetric. + Scalar c0 = m(0,0)*m(1,1)*m(2,2) + Scalar(2)*m(1,0)*m(2,0)*m(2,1) - m(0,0)*m(2,1)*m(2,1) - m(1,1)*m(2,0)*m(2,0) - m(2,2)*m(1,0)*m(1,0); + Scalar c1 = m(0,0)*m(1,1) - m(1,0)*m(1,0) + m(0,0)*m(2,2) - m(2,0)*m(2,0) + m(1,1)*m(2,2) - m(2,1)*m(2,1); + Scalar c2 = m(0,0) + m(1,1) + m(2,2); + + // Construct the parameters used in classifying the roots of the equation + // and in solving the equation for the roots in closed form. + Scalar c2_over_3 = c2*s_inv3; + Scalar a_over_3 = (c1 - c2*c2_over_3)*s_inv3; + if (a_over_3 > Scalar(0)) + a_over_3 = Scalar(0); + + Scalar half_b = Scalar(0.5)*(c0 + c2_over_3*(Scalar(2)*c2_over_3*c2_over_3 - c1)); + + Scalar q = half_b*half_b + a_over_3*a_over_3*a_over_3; + if (q > Scalar(0)) + q = Scalar(0); + + // Compute the eigenvalues by solving for the roots of the polynomial. + Scalar rho = sqrt(-a_over_3); + Scalar theta = atan2(sqrt(-q),half_b)*s_inv3; + Scalar cos_theta = cos(theta); + Scalar sin_theta = sin(theta); + roots(0) = c2_over_3 + Scalar(2)*rho*cos_theta; + roots(1) = c2_over_3 - rho*(cos_theta + s_sqrt3*sin_theta); + roots(2) = c2_over_3 - rho*(cos_theta - s_sqrt3*sin_theta); + + // Sort in increasing order. + if (roots(0) >= roots(1)) + std::swap(roots(0),roots(1)); + if (roots(1) >= roots(2)) + { + std::swap(roots(1),roots(2)); + if (roots(0) >= roots(1)) + std::swap(roots(0),roots(1)); + } + } + + static inline void run(SolverType& solver, const MatrixType& mat, int options) + { + using std::sqrt; + eigen_assert(mat.cols() == 3 && mat.cols() == mat.rows()); + eigen_assert((options&~(EigVecMask|GenEigMask))==0 + && (options&EigVecMask)!=EigVecMask + && "invalid option parameter"); + bool computeEigenvectors = (options&ComputeEigenvectors)==ComputeEigenvectors; + + MatrixType& eivecs = solver.m_eivec; + VectorType& eivals = solver.m_eivalues; + + // map the matrix coefficients to [-1:1] to avoid over- and underflow. + Scalar scale = mat.cwiseAbs().maxCoeff(); + MatrixType scaledMat = mat / scale; + + // compute the eigenvalues + computeRoots(scaledMat,eivals); + + // compute the eigen vectors + if(computeEigenvectors) + { + Scalar safeNorm2 = Eigen::NumTraits::epsilon(); + safeNorm2 *= safeNorm2; + if((eivals(2)-eivals(0))<=Eigen::NumTraits::epsilon()) + { + eivecs.setIdentity(); + } + else + { + scaledMat = scaledMat.template selfadjointView(); + MatrixType tmp; + tmp = scaledMat; + + Scalar d0 = eivals(2) - eivals(1); + Scalar d1 = eivals(1) - eivals(0); + int k = d0 > d1 ? 2 : 0; + d0 = d0 > d1 ? d1 : d0; + + tmp.diagonal().array () -= eivals(k); + VectorType cross; + Scalar n; + n = (cross = tmp.row(0).cross(tmp.row(1))).squaredNorm(); + + if(n>safeNorm2) + eivecs.col(k) = cross / sqrt(n); + else + { + n = (cross = tmp.row(0).cross(tmp.row(2))).squaredNorm(); + + if(n>safeNorm2) + eivecs.col(k) = cross / sqrt(n); + else + { + n = (cross = tmp.row(1).cross(tmp.row(2))).squaredNorm(); + + if(n>safeNorm2) + eivecs.col(k) = cross / sqrt(n); + else + { + // the input matrix and/or the eigenvaues probably contains some inf/NaN, + // => exit + // scale back to the original size. + eivals *= scale; + + solver.m_info = NumericalIssue; + solver.m_isInitialized = true; + solver.m_eigenvectorsOk = computeEigenvectors; + return; + } + } + } + + tmp = scaledMat; + tmp.diagonal().array() -= eivals(1); + + if(d0<=Eigen::NumTraits::epsilon()) + eivecs.col(1) = eivecs.col(k).unitOrthogonal(); + else + { + n = (cross = eivecs.col(k).cross(tmp.row(0).normalized())).squaredNorm(); + if(n>safeNorm2) + eivecs.col(1) = cross / sqrt(n); + else + { + n = (cross = eivecs.col(k).cross(tmp.row(1))).squaredNorm(); + if(n>safeNorm2) + eivecs.col(1) = cross / sqrt(n); + else + { + n = (cross = eivecs.col(k).cross(tmp.row(2))).squaredNorm(); + if(n>safeNorm2) + eivecs.col(1) = cross / sqrt(n); + else + { + // we should never reach this point, + // if so the last two eigenvalues are likely to ve very closed to each other + eivecs.col(1) = eivecs.col(k).unitOrthogonal(); + } + } + } + + // make sure that eivecs[1] is orthogonal to eivecs[2] + Scalar d = eivecs.col(1).dot(eivecs.col(k)); + eivecs.col(1) = (eivecs.col(1) - d * eivecs.col(k)).normalized(); + } + + eivecs.col(k==2 ? 0 : 2) = eivecs.col(k).cross(eivecs.col(1)).normalized(); + } + } + // Rescale back to the original size. + eivals *= scale; + + solver.m_info = Success; + solver.m_isInitialized = true; + solver.m_eigenvectorsOk = computeEigenvectors; + } +}; + +// 2x2 direct eigenvalues decomposition, code from Hauke Heibel +template struct direct_selfadjoint_eigenvalues +{ + typedef typename SolverType::MatrixType MatrixType; + typedef typename SolverType::RealVectorType VectorType; + typedef typename SolverType::Scalar Scalar; + + static inline void computeRoots(const MatrixType& m, VectorType& roots) + { + using std::sqrt; + const Scalar t0 = Scalar(0.5) * sqrt( abs2(m(0,0)-m(1,1)) + Scalar(4)*m(1,0)*m(1,0)); + const Scalar t1 = Scalar(0.5) * (m(0,0) + m(1,1)); + roots(0) = t1 - t0; + roots(1) = t1 + t0; + } + + static inline void run(SolverType& solver, const MatrixType& mat, int options) + { + eigen_assert(mat.cols() == 2 && mat.cols() == mat.rows()); + eigen_assert((options&~(EigVecMask|GenEigMask))==0 + && (options&EigVecMask)!=EigVecMask + && "invalid option parameter"); + bool computeEigenvectors = (options&ComputeEigenvectors)==ComputeEigenvectors; + + MatrixType& eivecs = solver.m_eivec; + VectorType& eivals = solver.m_eivalues; + + // map the matrix coefficients to [-1:1] to avoid over- and underflow. + Scalar scale = mat.cwiseAbs().maxCoeff(); + scale = (std::max)(scale,Scalar(1)); + MatrixType scaledMat = mat / scale; + + // Compute the eigenvalues + computeRoots(scaledMat,eivals); + + // compute the eigen vectors + if(computeEigenvectors) + { + scaledMat.diagonal().array () -= eivals(1); + Scalar a2 = abs2(scaledMat(0,0)); + Scalar c2 = abs2(scaledMat(1,1)); + Scalar b2 = abs2(scaledMat(1,0)); + if(a2>c2) + { + eivecs.col(1) << -scaledMat(1,0), scaledMat(0,0); + eivecs.col(1) /= sqrt(a2+b2); + } + else + { + eivecs.col(1) << -scaledMat(1,1), scaledMat(1,0); + eivecs.col(1) /= sqrt(c2+b2); + } + + eivecs.col(0) << eivecs.col(1).unitOrthogonal(); + } + + // Rescale back to the original size. + eivals *= scale; + + solver.m_info = Success; + solver.m_isInitialized = true; + solver.m_eigenvectorsOk = computeEigenvectors; + } +}; + +} + +template +SelfAdjointEigenSolver& SelfAdjointEigenSolver +::computeDirect(const MatrixType& matrix, int options) +{ + internal::direct_selfadjoint_eigenvalues::IsComplex>::run(*this,matrix,options); + return *this; +} + namespace internal { template static void tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index start, Index end, Scalar* matrixQ, Index n) { - // NOTE this version avoids over & underflow, however since the matrix is prescaled, overflow cannot occur, - // and underflows should be meaningless anyway. So I don't any reason to enable this version, but I keep - // it here for reference: -// RealScalar td = (diag[end-1] - diag[end])*RealScalar(0.5); -// RealScalar e = subdiag[end-1]; -// RealScalar mu = diag[end] - (e / (td + (td>0 ? 1 : -1))) * (e / hypot(td,e)); RealScalar td = (diag[end-1] - diag[end])*RealScalar(0.5); - RealScalar e2 = abs2(subdiag[end-1]); - RealScalar mu = diag[end] - e2 / (td + (td>0 ? 1 : -1) * sqrt(td*td + e2)); + RealScalar e = subdiag[end-1]; + // Note that thanks to scaling, e^2 or td^2 cannot overflow, however they can still + // underflow thus leading to inf/NaN values when using the following commented code: +// RealScalar e2 = abs2(subdiag[end-1]); +// RealScalar mu = diag[end] - e2 / (td + (td>0 ? 1 : -1) * sqrt(td*td + e2)); + // This explain the following, somewhat more complicated, version: + RealScalar mu = diag[end] - (e / (td + (td>0 ? 1 : -1))) * (e / hypot(td,e)); + RealScalar x = diag[start] - mu; RealScalar z = subdiag[start]; for (Index k = start; k < end; ++k) @@ -515,6 +781,9 @@ static void tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index sta } } } + } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_SELFADJOINTEIGENSOLVER_H diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_MKL.h b/extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_MKL.h new file mode 100644 index 00000000000..9380956b5f9 --- /dev/null +++ b/extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_MKL.h @@ -0,0 +1,92 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * Self-adjoint eigenvalues/eigenvectors. + ******************************************************************************** +*/ + +#ifndef EIGEN_SAEIGENSOLVER_MKL_H +#define EIGEN_SAEIGENSOLVER_MKL_H + +#include "Eigen/src/Core/util/MKL_support.h" + +namespace Eigen { + +/** \internal Specialization for the data types supported by MKL */ + +#define EIGEN_MKL_EIG_SELFADJ(EIGTYPE, MKLTYPE, MKLRTYPE, MKLNAME, EIGCOLROW, MKLCOLROW ) \ +template<> inline\ +SelfAdjointEigenSolver >& \ +SelfAdjointEigenSolver >::compute(const Matrix& matrix, int options) \ +{ \ + eigen_assert(matrix.cols() == matrix.rows()); \ + eigen_assert((options&~(EigVecMask|GenEigMask))==0 \ + && (options&EigVecMask)!=EigVecMask \ + && "invalid option parameter"); \ + bool computeEigenvectors = (options&ComputeEigenvectors)==ComputeEigenvectors; \ + lapack_int n = matrix.cols(), lda, matrix_order, info; \ + m_eivalues.resize(n,1); \ + m_subdiag.resize(n-1); \ + m_eivec = matrix; \ +\ + if(n==1) \ + { \ + m_eivalues.coeffRef(0,0) = internal::real(matrix.coeff(0,0)); \ + if(computeEigenvectors) m_eivec.setOnes(n,n); \ + m_info = Success; \ + m_isInitialized = true; \ + m_eigenvectorsOk = computeEigenvectors; \ + return *this; \ + } \ +\ + lda = matrix.outerStride(); \ + matrix_order=MKLCOLROW; \ + char jobz, uplo='L'/*, range='A'*/; \ + jobz = computeEigenvectors ? 'V' : 'N'; \ +\ + info = LAPACKE_##MKLNAME( matrix_order, jobz, uplo, n, (MKLTYPE*)m_eivec.data(), lda, (MKLRTYPE*)m_eivalues.data() ); \ + m_info = (info==0) ? Success : NoConvergence; \ + m_isInitialized = true; \ + m_eigenvectorsOk = computeEigenvectors; \ + return *this; \ +} + + +EIGEN_MKL_EIG_SELFADJ(double, double, double, dsyev, ColMajor, LAPACK_COL_MAJOR) +EIGEN_MKL_EIG_SELFADJ(float, float, float, ssyev, ColMajor, LAPACK_COL_MAJOR) +EIGEN_MKL_EIG_SELFADJ(dcomplex, MKL_Complex16, double, zheev, ColMajor, LAPACK_COL_MAJOR) +EIGEN_MKL_EIG_SELFADJ(scomplex, MKL_Complex8, float, cheev, ColMajor, LAPACK_COL_MAJOR) + +EIGEN_MKL_EIG_SELFADJ(double, double, double, dsyev, RowMajor, LAPACK_ROW_MAJOR) +EIGEN_MKL_EIG_SELFADJ(float, float, float, ssyev, RowMajor, LAPACK_ROW_MAJOR) +EIGEN_MKL_EIG_SELFADJ(dcomplex, MKL_Complex16, double, zheev, RowMajor, LAPACK_ROW_MAJOR) +EIGEN_MKL_EIG_SELFADJ(scomplex, MKL_Complex8, float, cheev, RowMajor, LAPACK_ROW_MAJOR) + +} // end namespace Eigen + +#endif // EIGEN_SAEIGENSOLVER_H diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/Tridiagonalization.h b/extern/Eigen3/Eigen/src/Eigenvalues/Tridiagonalization.h index ae4cdce7aeb..c34b7b3b801 100644 --- a/extern/Eigen3/Eigen/src/Eigenvalues/Tridiagonalization.h +++ b/extern/Eigen3/Eigen/src/Eigenvalues/Tridiagonalization.h @@ -4,28 +4,15 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2010 Jitse Niesen // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_TRIDIAGONALIZATION_H #define EIGEN_TRIDIAGONALIZATION_H +namespace Eigen { + namespace internal { template struct TridiagonalizationMatrixTReturnType; @@ -97,13 +84,13 @@ template class Tridiagonalization typedef internal::TridiagonalizationMatrixTReturnType MatrixTReturnType; typedef typename internal::conditional::IsComplex, - const typename Diagonal::RealReturnType, + typename internal::add_const_on_value_type::RealReturnType>::type, const Diagonal >::type DiagonalReturnType; typedef typename internal::conditional::IsComplex, - const typename Diagonal< - Block >::RealReturnType, + typename internal::add_const_on_value_type >::RealReturnType>::type, const Diagonal< Block > >::type SubDiagonalReturnType; @@ -560,9 +547,11 @@ template struct TridiagonalizationMatrixTReturnType Index cols() const { return m_matrix.cols(); } protected: - const typename MatrixType::Nested m_matrix; + typename MatrixType::Nested m_matrix; }; } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_TRIDIAGONALIZATION_H diff --git a/extern/Eigen3/Eigen/src/Geometry/AlignedBox.h b/extern/Eigen3/Eigen/src/Geometry/AlignedBox.h index b51deb3f3c3..5830fcd35fc 100644 --- a/extern/Eigen3/Eigen/src/Geometry/AlignedBox.h +++ b/extern/Eigen3/Eigen/src/Geometry/AlignedBox.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ALIGNEDBOX_H #define EIGEN_ALIGNEDBOX_H +namespace Eigen { + /** \geometry_module \ingroup Geometry_Module * * @@ -190,7 +177,7 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) template inline bool contains(const MatrixBase& a_p) const { - const typename internal::nested::type p(a_p.derived()); + typename internal::nested::type p(a_p.derived()); return (m_min.array()<=p.array()).all() && (p.array()<=m_max.array()).all(); } @@ -202,7 +189,7 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) template inline AlignedBox& extend(const MatrixBase& a_p) { - const typename internal::nested::type p(a_p.derived()); + typename internal::nested::type p(a_p.derived()); m_min = m_min.cwiseMin(p); m_max = m_max.cwiseMax(p); return *this; @@ -310,7 +297,7 @@ template inline Scalar AlignedBox::squaredExteriorDistance(const MatrixBase& a_p) const { const typename internal::nested::type p(a_p.derived()); - Scalar dist2 = 0.; + Scalar dist2(0); Scalar aux; for (Index k=0; k::squaredExteriorDistance(const Matri template inline Scalar AlignedBox::squaredExteriorDistance(const AlignedBox& b) const { - Scalar dist2 = 0.; + Scalar dist2(0); Scalar aux; for (Index k=0; k::squaredExteriorDistance(const Align return dist2; } +/** \defgroup alignedboxtypedefs Global aligned box typedefs + * + * \ingroup Geometry_Module + * + * Eigen defines several typedef shortcuts for most common aligned box types. + * + * The general patterns are the following: + * + * \c AlignedBoxSizeType where \c Size can be \c 1, \c 2,\c 3,\c 4 for fixed size boxes or \c X for dynamic size, + * and where \c Type can be \c i for integer, \c f for float, \c d for double. + * + * For example, \c AlignedBox3d is a fixed-size 3x3 aligned box type of doubles, and \c AlignedBoxXf is a dynamic-size aligned box of floats. + * + * \sa class AlignedBox + */ + +#define EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \ +/** \ingroup alignedboxtypedefs */ \ +typedef AlignedBox AlignedBox##SizeSuffix##TypeSuffix; + +#define EIGEN_MAKE_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \ +EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 1, 1) \ +EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 2, 2) \ +EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 3, 3) \ +EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 4, 4) \ +EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Dynamic, X) + +EIGEN_MAKE_TYPEDEFS_ALL_SIZES(int, i) +EIGEN_MAKE_TYPEDEFS_ALL_SIZES(float, f) +EIGEN_MAKE_TYPEDEFS_ALL_SIZES(double, d) + +#undef EIGEN_MAKE_TYPEDEFS_ALL_SIZES +#undef EIGEN_MAKE_TYPEDEFS + +} // end namespace Eigen + #endif // EIGEN_ALIGNEDBOX_H diff --git a/extern/Eigen3/Eigen/src/Geometry/AngleAxis.h b/extern/Eigen3/Eigen/src/Geometry/AngleAxis.h index 0ec4624cf98..67197ac78c3 100644 --- a/extern/Eigen3/Eigen/src/Geometry/AngleAxis.h +++ b/extern/Eigen3/Eigen/src/Geometry/AngleAxis.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ANGLEAXIS_H #define EIGEN_ANGLEAXIS_H +namespace Eigen { + /** \geometry_module \ingroup Geometry_Module * * \class AngleAxis @@ -144,7 +131,7 @@ public: m_angle = Scalar(other.angle()); } - inline static const AngleAxis Identity() { return AngleAxis(0, Vector3::UnitX()); } + static inline const AngleAxis Identity() { return AngleAxis(0, Vector3::UnitX()); } /** \returns \c true if \c *this is approximately equal to \a other, within the precision * determined by \a prec. @@ -238,4 +225,6 @@ AngleAxis::toRotationMatrix(void) const return res; } +} // end namespace Eigen + #endif // EIGEN_ANGLEAXIS_H diff --git a/extern/Eigen3/Eigen/src/Geometry/EulerAngles.h b/extern/Eigen3/Eigen/src/Geometry/EulerAngles.h index d246a6ebf4a..e424d240604 100644 --- a/extern/Eigen3/Eigen/src/Geometry/EulerAngles.h +++ b/extern/Eigen3/Eigen/src/Geometry/EulerAngles.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_EULERANGLES_H #define EIGEN_EULERANGLES_H +namespace Eigen { + /** \geometry_module \ingroup Geometry_Module * * @@ -92,5 +79,6 @@ MatrixBase::eulerAngles(Index a0, Index a1, Index a2) const return res; } +} // end namespace Eigen #endif // EIGEN_EULERANGLES_H diff --git a/extern/Eigen3/Eigen/src/Geometry/Homogeneous.h b/extern/Eigen3/Eigen/src/Geometry/Homogeneous.h index 2bc4f7e87e3..df03feb55c6 100644 --- a/extern/Eigen3/Eigen/src/Geometry/Homogeneous.h +++ b/extern/Eigen3/Eigen/src/Geometry/Homogeneous.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_HOMOGENEOUS_H #define EIGEN_HOMOGENEOUS_H +namespace Eigen { + /** \geometry_module \ingroup Geometry_Module * * \class Homogeneous @@ -121,7 +108,7 @@ template class Homogeneous } protected: - const typename MatrixType::Nested m_matrix; + typename MatrixType::Nested m_matrix; }; /** \geometry_module @@ -216,8 +203,8 @@ template struct take_matrix_for_product > { typedef Transform TransformType; - typedef typename TransformType::ConstAffinePart type; - static const type run (const TransformType& x) { return x.affine(); } + typedef typename internal::add_const::type type; + static type run (const TransformType& x) { return x.affine(); } }; template @@ -270,8 +257,8 @@ struct homogeneous_left_product_impl,Lhs> .template replicate(m_rhs.cols()); } - const typename LhsMatrixTypeCleaned::Nested m_lhs; - const typename MatrixType::Nested m_rhs; + typename LhsMatrixTypeCleaned::Nested m_lhs; + typename MatrixType::Nested m_rhs; }; template @@ -309,10 +296,12 @@ struct homogeneous_right_product_impl,Rhs> .template replicate(m_lhs.rows()); } - const typename MatrixType::Nested m_lhs; - const typename Rhs::Nested m_rhs; + typename MatrixType::Nested m_lhs; + typename Rhs::Nested m_rhs; }; } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_HOMOGENEOUS_H diff --git a/extern/Eigen3/Eigen/src/Geometry/Hyperplane.h b/extern/Eigen3/Eigen/src/Geometry/Hyperplane.h index d85d3e553f8..1b7c7c78c80 100644 --- a/extern/Eigen3/Eigen/src/Geometry/Hyperplane.h +++ b/extern/Eigen3/Eigen/src/Geometry/Hyperplane.h @@ -4,28 +4,15 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_HYPERPLANE_H #define EIGEN_HYPERPLANE_H +namespace Eigen { + /** \geometry_module \ingroup Geometry_Module * * \class Hyperplane @@ -277,4 +264,6 @@ protected: Coefficients m_coeffs; }; +} // end namespace Eigen + #endif // EIGEN_HYPERPLANE_H diff --git a/extern/Eigen3/Eigen/src/Geometry/OrthoMethods.h b/extern/Eigen3/Eigen/src/Geometry/OrthoMethods.h index 52b46988196..11ad5829cda 100644 --- a/extern/Eigen3/Eigen/src/Geometry/OrthoMethods.h +++ b/extern/Eigen3/Eigen/src/Geometry/OrthoMethods.h @@ -4,28 +4,15 @@ // Copyright (C) 2008-2009 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ORTHOMETHODS_H #define EIGEN_ORTHOMETHODS_H +namespace Eigen { + /** \geometry_module * * \returns the cross product of \c *this and \a other @@ -43,8 +30,8 @@ MatrixBase::cross(const MatrixBase& other) const // Note that there is no need for an expression here since the compiler // optimize such a small temporary very well (even within a complex expression) - const typename internal::nested::type lhs(derived()); - const typename internal::nested::type rhs(other.derived()); + typename internal::nested::type lhs(derived()); + typename internal::nested::type rhs(other.derived()); return typename cross_product_return_type::type( internal::conj(lhs.coeff(1) * rhs.coeff(2) - lhs.coeff(2) * rhs.coeff(1)), internal::conj(lhs.coeff(2) * rhs.coeff(0) - lhs.coeff(0) * rhs.coeff(2)), @@ -56,9 +43,9 @@ namespace internal { template< int Arch,typename VectorLhs,typename VectorRhs, typename Scalar = typename VectorLhs::Scalar, - bool Vectorizable = (VectorLhs::Flags&VectorRhs::Flags)&PacketAccessBit> + bool Vectorizable = bool((VectorLhs::Flags&VectorRhs::Flags)&PacketAccessBit)> struct cross3_impl { - inline static typename internal::plain_matrix_type::type + static inline typename internal::plain_matrix_type::type run(const VectorLhs& lhs, const VectorRhs& rhs) { return typename internal::plain_matrix_type::type( @@ -145,7 +132,7 @@ struct unitOrthogonal_selector typedef typename NumTraits::Real RealScalar; typedef typename Derived::Index Index; typedef Matrix Vector2; - inline static VectorType run(const Derived& src) + static inline VectorType run(const Derived& src) { VectorType perp = VectorType::Zero(src.size()); Index maxi = 0; @@ -167,7 +154,7 @@ struct unitOrthogonal_selector typedef typename plain_matrix_type::type VectorType; typedef typename traits::Scalar Scalar; typedef typename NumTraits::Real RealScalar; - inline static VectorType run(const Derived& src) + static inline VectorType run(const Derived& src) { VectorType perp; /* Let us compute the crossed product of *this with a vector @@ -205,7 +192,7 @@ template struct unitOrthogonal_selector { typedef typename plain_matrix_type::type VectorType; - inline static VectorType run(const Derived& src) + static inline VectorType run(const Derived& src) { return VectorType(-conj(src.y()), conj(src.x())).normalized(); } }; @@ -226,4 +213,6 @@ MatrixBase::unitOrthogonal() const return internal::unitOrthogonal_selector::run(derived()); } +} // end namespace Eigen + #endif // EIGEN_ORTHOMETHODS_H diff --git a/extern/Eigen3/Eigen/src/Geometry/ParametrizedLine.h b/extern/Eigen3/Eigen/src/Geometry/ParametrizedLine.h index b90f9c088a2..719a904413d 100644 --- a/extern/Eigen3/Eigen/src/Geometry/ParametrizedLine.h +++ b/extern/Eigen3/Eigen/src/Geometry/ParametrizedLine.h @@ -4,28 +4,15 @@ // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_PARAMETRIZEDLINE_H #define EIGEN_PARAMETRIZEDLINE_H +namespace Eigen { + /** \geometry_module \ingroup Geometry_Module * * \class ParametrizedLine @@ -106,8 +93,16 @@ public: VectorType projection(const VectorType& p) const { return origin() + direction().dot(p-origin()) * direction(); } + VectorType pointAt( Scalar t ) const; + + template + Scalar intersectionParameter(const Hyperplane<_Scalar, _AmbientDim, OtherOptions>& hyperplane) const; + template Scalar intersection(const Hyperplane<_Scalar, _AmbientDim, OtherOptions>& hyperplane) const; + + template + VectorType intersectionPoint(const Hyperplane<_Scalar, _AmbientDim, OtherOptions>& hyperplane) const; /** \returns \c *this with scalar type casted to \a NewScalarType * @@ -155,14 +150,46 @@ inline ParametrizedLine<_Scalar, _AmbientDim,_Options>::ParametrizedLine(const H origin() = -hyperplane.normal()*hyperplane.offset(); } -/** \returns the parameter value of the intersection between \c *this and the given hyperplane +/** \returns the point at \a t along this line + */ +template +inline typename ParametrizedLine<_Scalar, _AmbientDim,_Options>::VectorType +ParametrizedLine<_Scalar, _AmbientDim,_Options>::pointAt( _Scalar t ) const +{ + return origin() + (direction()*t); +} + +/** \returns the parameter value of the intersection between \c *this and the given \a hyperplane */ template template -inline _Scalar ParametrizedLine<_Scalar, _AmbientDim,_Options>::intersection(const Hyperplane<_Scalar, _AmbientDim, OtherOptions>& hyperplane) const +inline _Scalar ParametrizedLine<_Scalar, _AmbientDim,_Options>::intersectionParameter(const Hyperplane<_Scalar, _AmbientDim, OtherOptions>& hyperplane) const { return -(hyperplane.offset()+hyperplane.normal().dot(origin())) / hyperplane.normal().dot(direction()); } + +/** \deprecated use intersectionParameter() + * \returns the parameter value of the intersection between \c *this and the given \a hyperplane + */ +template +template +inline _Scalar ParametrizedLine<_Scalar, _AmbientDim,_Options>::intersection(const Hyperplane<_Scalar, _AmbientDim, OtherOptions>& hyperplane) const +{ + return intersectionParameter(hyperplane); +} + +/** \returns the point of the intersection between \c *this and the given hyperplane + */ +template +template +inline typename ParametrizedLine<_Scalar, _AmbientDim,_Options>::VectorType +ParametrizedLine<_Scalar, _AmbientDim,_Options>::intersectionPoint(const Hyperplane<_Scalar, _AmbientDim, OtherOptions>& hyperplane) const +{ + return pointAt(intersectionParameter(hyperplane)); +} + +} // end namespace Eigen + #endif // EIGEN_PARAMETRIZEDLINE_H diff --git a/extern/Eigen3/Eigen/src/Geometry/Quaternion.h b/extern/Eigen3/Eigen/src/Geometry/Quaternion.h index 9180db67d84..8792e2da2ae 100644 --- a/extern/Eigen3/Eigen/src/Geometry/Quaternion.h +++ b/extern/Eigen3/Eigen/src/Geometry/Quaternion.h @@ -4,27 +4,14 @@ // Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2009 Mathieu Gautier // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_QUATERNION_H #define EIGEN_QUATERNION_H +namespace Eigen { + /*************************************************************************** * Definition of QuaternionBase @@ -38,6 +25,12 @@ template class QuaternionBase : public RotationBase { @@ -109,7 +102,7 @@ public: /** \returns a quaternion representing an identity rotation * \sa MatrixBase::Identity() */ - inline static Quaternion Identity() { return Quaternion(1, 0, 0, 0); } + static inline Quaternion Identity() { return Quaternion(1, 0, 0, 0); } /** \sa QuaternionBase::Identity(), MatrixBase::setIdentity() */ @@ -278,6 +271,9 @@ public: explicit inline Quaternion(const Quaternion& other) { m_coeffs = other.coeffs().template cast(); } + template + static Quaternion FromTwoVectors(const MatrixBase& a, const MatrixBase& b); + inline Coefficients& coeffs() { return m_coeffs;} inline const Coefficients& coeffs() const { return m_coeffs;} @@ -287,7 +283,7 @@ protected: Coefficients m_coeffs; #ifndef EIGEN_PARSED_BY_DOXYGEN - EIGEN_STRONG_INLINE static void _check_template_params() + static EIGEN_STRONG_INLINE void _check_template_params() { EIGEN_STATIC_ASSERT( (_Options & DontAlign) == _Options, INVALID_MATRIX_TEMPLATE_PARAMETERS) @@ -434,7 +430,7 @@ typedef Map, Aligned> QuaternionMapAlignedd; namespace internal { template struct quat_product { - EIGEN_STRONG_INLINE static Quaternion run(const QuaternionBase& a, const QuaternionBase& b){ + static EIGEN_STRONG_INLINE Quaternion run(const QuaternionBase& a, const QuaternionBase& b){ return Quaternion ( a.w() * b.w() - a.x() * b.x() - a.y() * b.y() - a.z() * b.z(), @@ -544,9 +540,9 @@ QuaternionBase::toRotationMatrix(void) const // it has to be inlined, and so the return by value is not an issue Matrix3 res; - const Scalar tx = 2*this->x(); - const Scalar ty = 2*this->y(); - const Scalar tz = 2*this->z(); + const Scalar tx = Scalar(2)*this->x(); + const Scalar ty = Scalar(2)*this->y(); + const Scalar tz = Scalar(2)*this->z(); const Scalar twx = tx*this->w(); const Scalar twy = ty*this->w(); const Scalar twz = tz*this->w(); @@ -557,15 +553,15 @@ QuaternionBase::toRotationMatrix(void) const const Scalar tyz = tz*this->y(); const Scalar tzz = tz*this->z(); - res.coeffRef(0,0) = 1-(tyy+tzz); + res.coeffRef(0,0) = Scalar(1)-(tyy+tzz); res.coeffRef(0,1) = txy-twz; res.coeffRef(0,2) = txz+twy; res.coeffRef(1,0) = txy+twz; - res.coeffRef(1,1) = 1-(txx+tzz); + res.coeffRef(1,1) = Scalar(1)-(txx+tzz); res.coeffRef(1,2) = tyz-twx; res.coeffRef(2,0) = txz-twy; res.coeffRef(2,1) = tyz+twx; - res.coeffRef(2,2) = 1-(txx+tyy); + res.coeffRef(2,2) = Scalar(1)-(txx+tyy); return res; } @@ -618,6 +614,27 @@ inline Derived& QuaternionBase::setFromTwoVectors(const MatrixBase +template +Quaternion Quaternion::FromTwoVectors(const MatrixBase& a, const MatrixBase& b) +{ + Quaternion quat; + quat.setFromTwoVectors(a, b); + return quat; +} + + /** \returns the multiplicative inverse of \c *this * Note that in most cases, i.e., if you simply want the opposite rotation, * and/or the quaternion is normalized, then it is enough to use the conjugate. @@ -709,7 +726,7 @@ struct quaternionbase_assign_impl { typedef typename Other::Scalar Scalar; typedef DenseIndex Index; - template inline static void run(QuaternionBase& q, const Other& mat) + template static inline void run(QuaternionBase& q, const Other& mat) { // This algorithm comes from "Quaternion Calculus and Fast Animation", // Ken Shoemake, 1987 SIGGRAPH course notes @@ -748,7 +765,7 @@ template struct quaternionbase_assign_impl { typedef typename Other::Scalar Scalar; - template inline static void run(QuaternionBase& q, const Other& vec) + template static inline void run(QuaternionBase& q, const Other& vec) { q.coeffs() = vec; } @@ -756,4 +773,6 @@ struct quaternionbase_assign_impl } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_QUATERNION_H diff --git a/extern/Eigen3/Eigen/src/Geometry/Rotation2D.h b/extern/Eigen3/Eigen/src/Geometry/Rotation2D.h index cf36da1c50c..868e2ef312f 100644 --- a/extern/Eigen3/Eigen/src/Geometry/Rotation2D.h +++ b/extern/Eigen3/Eigen/src/Geometry/Rotation2D.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ROTATION2D_H #define EIGEN_ROTATION2D_H +namespace Eigen { + /** \geometry_module \ingroup Geometry_Module * * \class Rotation2D @@ -121,7 +108,7 @@ public: m_angle = Scalar(other.angle()); } - inline static Rotation2D Identity() { return Rotation2D(0); } + static inline Rotation2D Identity() { return Rotation2D(0); } /** \returns \c true if \c *this is approximately equal to \a other, within the precision * determined by \a prec. @@ -162,4 +149,6 @@ Rotation2D::toRotationMatrix(void) const return (Matrix2() << cosA, -sinA, sinA, cosA).finished(); } +} // end namespace Eigen + #endif // EIGEN_ROTATION2D_H diff --git a/extern/Eigen3/Eigen/src/Geometry/RotationBase.h b/extern/Eigen3/Eigen/src/Geometry/RotationBase.h index 1abf06bb640..b88661de6b1 100644 --- a/extern/Eigen3/Eigen/src/Geometry/RotationBase.h +++ b/extern/Eigen3/Eigen/src/Geometry/RotationBase.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ROTATIONBASE_H #define EIGEN_ROTATIONBASE_H +namespace Eigen { + // forward declaration namespace internal { template @@ -115,7 +102,7 @@ struct rotation_base_generic_product_selector { enum { Dim = RotationDerived::Dim }; typedef Matrix ReturnType; - inline static ReturnType run(const RotationDerived& r, const MatrixType& m) + static inline ReturnType run(const RotationDerived& r, const MatrixType& m) { return r.toRotationMatrix() * m; } }; @@ -123,7 +110,7 @@ template struct rotation_base_generic_product_selector< RotationDerived, DiagonalMatrix, false > { typedef Transform ReturnType; - inline static ReturnType run(const RotationDerived& r, const DiagonalMatrix& m) + static inline ReturnType run(const RotationDerived& r, const DiagonalMatrix& m) { ReturnType res(r); res.linear() *= m; @@ -136,7 +123,7 @@ struct rotation_base_generic_product_selector ReturnType; - EIGEN_STRONG_INLINE static ReturnType run(const RotationDerived& r, const OtherVectorType& v) + static EIGEN_STRONG_INLINE ReturnType run(const RotationDerived& r, const OtherVectorType& v) { return r._transformVector(v); } @@ -192,20 +179,20 @@ namespace internal { * \sa class Transform, class Rotation2D, class Quaternion, class AngleAxis */ template -inline static Matrix toRotationMatrix(const Scalar& s) +static inline Matrix toRotationMatrix(const Scalar& s) { EIGEN_STATIC_ASSERT(Dim==2,YOU_MADE_A_PROGRAMMING_MISTAKE) return Rotation2D(s).toRotationMatrix(); } template -inline static Matrix toRotationMatrix(const RotationBase& r) +static inline Matrix toRotationMatrix(const RotationBase& r) { return r.toRotationMatrix(); } template -inline static const MatrixBase& toRotationMatrix(const MatrixBase& mat) +static inline const MatrixBase& toRotationMatrix(const MatrixBase& mat) { EIGEN_STATIC_ASSERT(OtherDerived::RowsAtCompileTime==Dim && OtherDerived::ColsAtCompileTime==Dim, YOU_MADE_A_PROGRAMMING_MISTAKE) @@ -214,4 +201,6 @@ inline static const MatrixBase& toRotationMatrix(const MatrixBase< } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_ROTATIONBASE_H diff --git a/extern/Eigen3/Eigen/src/Geometry/Scaling.h b/extern/Eigen3/Eigen/src/Geometry/Scaling.h index c911d13e1d3..8edcac31c74 100644 --- a/extern/Eigen3/Eigen/src/Geometry/Scaling.h +++ b/extern/Eigen3/Eigen/src/Geometry/Scaling.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SCALING_H #define EIGEN_SCALING_H +namespace Eigen { + /** \geometry_module \ingroup Geometry_Module * * \class Scaling @@ -73,7 +60,12 @@ public: /** Concatenates a uniform scaling and an affine transformation */ template - inline Transform operator* (const Transform& t) const; + inline Transform operator* (const Transform& t) const + { + Transform res = t; + res.prescale(factor()); + return res; +} /** Concatenates a uniform scaling and a linear transformation matrix */ // TODO returns an expression @@ -169,14 +161,6 @@ UniformScaling::operator* (const Translation& t) const return res; } -template -template -inline Transform -UniformScaling::operator* (const Transform& t) const -{ - Transform res = t; - res.prescale(factor()); - return res; -} +} // end namespace Eigen #endif // EIGEN_SCALING_H diff --git a/extern/Eigen3/Eigen/src/Geometry/Transform.h b/extern/Eigen3/Eigen/src/Geometry/Transform.h index a694673ebed..4c1ef8eaade 100644 --- a/extern/Eigen3/Eigen/src/Geometry/Transform.h +++ b/extern/Eigen3/Eigen/src/Geometry/Transform.h @@ -5,28 +5,15 @@ // Copyright (C) 2009 Benoit Jacob // Copyright (C) 2010 Hauke Heibel // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_TRANSFORM_H #define EIGEN_TRANSFORM_H +namespace Eigen { + namespace internal { template @@ -37,7 +24,7 @@ struct transform_traits Dim = Transform::Dim, HDim = Transform::HDim, Mode = Transform::Mode, - IsProjective = (Mode==Projective) + IsProjective = (int(Mode)==int(Projective)) }; }; @@ -207,9 +194,9 @@ public: /** type of the matrix used to represent the linear part of the transformation */ typedef Matrix LinearMatrixType; /** type of read/write reference to the linear part of the transformation */ - typedef Block LinearPart; + typedef Block LinearPart; /** type of read reference to the linear part of the transformation */ - typedef const Block ConstLinearPart; + typedef const Block ConstLinearPart; /** type of read/write reference to the affine part of the transformation */ typedef typename internal::conditional VectorType; /** type of a read/write reference to the translation part of the rotation */ - typedef Block TranslationPart; + typedef Block TranslationPart; /** type of a read reference to the translation part of the rotation */ - typedef const Block ConstTranslationPart; + typedef const Block ConstTranslationPart; /** corresponding translation type */ typedef Translation TranslationType; @@ -279,6 +266,9 @@ public: template inline explicit Transform(const EigenBase& other) { + EIGEN_STATIC_ASSERT((internal::is_same::value), + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY); + check_template_params(); internal::transform_construct_from_matrix::run(this, other.derived()); } @@ -287,6 +277,9 @@ public: template inline Transform& operator=(const EigenBase& other) { + EIGEN_STATIC_ASSERT((internal::is_same::value), + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY); + internal::transform_construct_from_matrix::run(this, other.derived()); return *this; } @@ -376,9 +369,9 @@ public: inline MatrixType& matrix() { return m_matrix; } /** \returns a read-only expression of the linear part of the transformation */ - inline ConstLinearPart linear() const { return m_matrix.template block(0,0); } + inline ConstLinearPart linear() const { return ConstLinearPart(m_matrix,0,0); } /** \returns a writable expression of the linear part of the transformation */ - inline LinearPart linear() { return m_matrix.template block(0,0); } + inline LinearPart linear() { return LinearPart(m_matrix,0,0); } /** \returns a read-only expression of the Dim x HDim affine part of the transformation */ inline ConstAffinePart affine() const { return take_affine_part::run(m_matrix); } @@ -386,9 +379,9 @@ public: inline AffinePart affine() { return take_affine_part::run(m_matrix); } /** \returns a read-only expression of the translation vector of the transformation */ - inline ConstTranslationPart translation() const { return m_matrix.template block(0,Dim); } + inline ConstTranslationPart translation() const { return ConstTranslationPart(m_matrix,0,Dim); } /** \returns a writable expression of the translation vector of the transformation */ - inline TranslationPart translation() { return m_matrix.template block(0,Dim); } + inline TranslationPart translation() { return TranslationPart(m_matrix,0,Dim); } /** \returns an expression of the product between the transform \c *this and a matrix expression \a other * @@ -460,15 +453,40 @@ public: { return internal::transform_transform_product_impl::run(*this,other); } - + + #ifdef __INTEL_COMPILER +private: + // this intermediate structure permits to workaround a bug in ICC 11: + // error: template instantiation resulted in unexpected function type of "Eigen::Transform + // (const Eigen::Transform &) const" + // (the meaning of a name may have changed since the template declaration -- the type of the template is: + // "Eigen::internal::transform_transform_product_impl, + // Eigen::Transform, >::ResultType (const Eigen::Transform &) const") + // + template struct icc_11_workaround + { + typedef internal::transform_transform_product_impl > ProductType; + typedef typename ProductType::ResultType ResultType; + }; + +public: + /** Concatenates two different transformations */ + template + inline typename icc_11_workaround::ResultType + operator * (const Transform& other) const + { + typedef typename icc_11_workaround::ProductType ProductType; + return ProductType::run(*this,other); + } + #else /** Concatenates two different transformations */ template - inline const typename internal::transform_transform_product_impl< - Transform,Transform >::ResultType + inline typename internal::transform_transform_product_impl >::ResultType operator * (const Transform& other) const { return internal::transform_transform_product_impl >::run(*this,other); } + #endif /** \sa MatrixBase::setIdentity() */ void setIdentity() { m_matrix.setIdentity(); } @@ -512,7 +530,12 @@ public: inline Transform& operator=(const UniformScaling& t); inline Transform& operator*=(const UniformScaling& s) { return scale(s.factor()); } - inline Transform operator*(const UniformScaling& s) const; + inline Transform operator*(const UniformScaling& s) const + { + Transform res = *this; + res.scale(s.factor()); + return res; + } inline Transform& operator*=(const DiagonalMatrix& s) { linear() *= s; return *this; } @@ -571,7 +594,7 @@ public: if(int(Mode)!=int(AffineCompact)) { matrix().template block<1,Dim>(Dim,0).setZero(); - matrix().coeffRef(Dim,Dim) = 1; + matrix().coeffRef(Dim,Dim) = Scalar(1); } } @@ -608,7 +631,7 @@ public: protected: #ifndef EIGEN_PARSED_BY_DOXYGEN - EIGEN_STRONG_INLINE static void check_template_params() + static EIGEN_STRONG_INLINE void check_template_params() { EIGEN_STATIC_ASSERT((Options & (DontAlign|RowMajor)) == Options, INVALID_MATRIX_TEMPLATE_PARAMETERS) } @@ -940,14 +963,6 @@ inline Transform& Transform::o return *this; } -template -inline Transform Transform::operator*(const UniformScaling& s) const -{ - Transform res = *this; - res.scale(s.factor()); - return res; -} - template template inline Transform& Transform::operator=(const RotationBase& r) @@ -1219,7 +1234,7 @@ struct transform_right_product_impl< TransformType, MatrixType, 0 > { typedef typename MatrixType::PlainObject ResultType; - EIGEN_STRONG_INLINE static ResultType run(const TransformType& T, const MatrixType& other) + static EIGEN_STRONG_INLINE ResultType run(const TransformType& T, const MatrixType& other) { return T.matrix() * other; } @@ -1237,11 +1252,11 @@ struct transform_right_product_impl< TransformType, MatrixType, 1 > typedef typename MatrixType::PlainObject ResultType; - EIGEN_STRONG_INLINE static ResultType run(const TransformType& T, const MatrixType& other) + static EIGEN_STRONG_INLINE ResultType run(const TransformType& T, const MatrixType& other) { EIGEN_STATIC_ASSERT(OtherRows==HDim, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES); - typedef Block TopLeftLhs; + typedef Block TopLeftLhs; ResultType res(other.rows(),other.cols()); TopLeftLhs(res, 0, 0, Dim, other.cols()).noalias() = T.affine() * other; @@ -1263,15 +1278,13 @@ struct transform_right_product_impl< TransformType, MatrixType, 2 > typedef typename MatrixType::PlainObject ResultType; - EIGEN_STRONG_INLINE static ResultType run(const TransformType& T, const MatrixType& other) + static EIGEN_STRONG_INLINE ResultType run(const TransformType& T, const MatrixType& other) { EIGEN_STATIC_ASSERT(OtherRows==Dim, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES); - typedef Block TopLeftLhs; - - ResultType res(other.rows(),other.cols()); - TopLeftLhs(res, 0, 0, Dim, other.cols()).noalias() = T.linear() * other; - TopLeftLhs(res, 0, 0, Dim, other.cols()).colwise() += T.translation(); + typedef Block TopLeftLhs; + ResultType res(Replicate(T.translation(),1,other.cols())); + TopLeftLhs(res, 0, 0, Dim, other.cols()).noalias() += T.linear() * other; return res; } @@ -1422,4 +1435,6 @@ struct transform_transform_product_impl // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_TRANSLATION_H #define EIGEN_TRANSLATION_H +namespace Eigen { + /** \geometry_module \ingroup Geometry_Module * * \class Translation @@ -54,6 +41,8 @@ public: typedef Matrix LinearMatrixType; /** corresponding affine transformation type */ typedef Transform AffineTransformType; + /** corresponding isometric transformation type */ + typedef Transform IsometryTransformType; protected: @@ -114,8 +103,8 @@ public: /** Concatenates a translation and a rotation */ template - inline AffineTransformType operator*(const RotationBase& r) const - { return *this * r.toRotationMatrix(); } + inline IsometryTransformType operator*(const RotationBase& r) const + { return *this * IsometryTransformType(r); } /** \returns the concatenation of a linear transformation \a l with the translation \a t */ // its a nightmare to define a templated friend function outside its declaration @@ -212,4 +201,6 @@ Translation::operator* (const EigenBase& linear) const return res; } +} // end namespace Eigen + #endif // EIGEN_TRANSLATION_H diff --git a/extern/Eigen3/Eigen/src/Geometry/Umeyama.h b/extern/Eigen3/Eigen/src/Geometry/Umeyama.h index b50f461730e..ac0939cde52 100644 --- a/extern/Eigen3/Eigen/src/Geometry/Umeyama.h +++ b/extern/Eigen3/Eigen/src/Geometry/Umeyama.h @@ -3,24 +3,9 @@ // // Copyright (C) 2009 Hauke Heibel // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_UMEYAMA_H #define EIGEN_UMEYAMA_H @@ -31,6 +16,8 @@ // * Eigen/SVD // * Eigen/Array +namespace Eigen { + #ifndef EIGEN_PARSED_BY_DOXYGEN // These helpers are required since it allows to use mixed types as parameters @@ -180,4 +167,6 @@ umeyama(const MatrixBase& src, const MatrixBase& dst, boo return Rt; } +} // end namespace Eigen + #endif // EIGEN_UMEYAMA_H diff --git a/extern/Eigen3/Eigen/src/Geometry/arch/Geometry_SSE.h b/extern/Eigen3/Eigen/src/Geometry/arch/Geometry_SSE.h index 2af32678d1c..3d8284f2d0c 100644 --- a/extern/Eigen3/Eigen/src/Geometry/arch/Geometry_SSE.h +++ b/extern/Eigen3/Eigen/src/Geometry/arch/Geometry_SSE.h @@ -4,34 +4,21 @@ // Copyright (C) 2009 Rohit Garg // Copyright (C) 2009-2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_GEOMETRY_SSE_H #define EIGEN_GEOMETRY_SSE_H +namespace Eigen { + namespace internal { template struct quat_product { - inline static Quaternion run(const QuaternionBase& _a, const QuaternionBase& _b) + static inline Quaternion run(const QuaternionBase& _a, const QuaternionBase& _b) { const __m128 mask = _mm_castsi128_ps(_mm_setr_epi32(0,0,0,0x80000000)); Quaternion res; @@ -53,7 +40,7 @@ struct quat_product template struct cross3_impl { - inline static typename plain_matrix_type::type + static inline typename plain_matrix_type::type run(const VectorLhs& lhs, const VectorRhs& rhs) { __m128 a = lhs.template packet(0); @@ -72,7 +59,7 @@ struct cross3_impl template struct quat_product { - inline static Quaternion run(const QuaternionBase& _a, const QuaternionBase& _b) + static inline Quaternion run(const QuaternionBase& _a, const QuaternionBase& _b) { const Packet2d mask = _mm_castsi128_pd(_mm_set_epi32(0x0,0x0,0x80000000,0x0)); @@ -123,4 +110,6 @@ struct quat_product } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_GEOMETRY_SSE_H diff --git a/extern/Eigen3/Eigen/src/Householder/BlockHouseholder.h b/extern/Eigen3/Eigen/src/Householder/BlockHouseholder.h index 23ce1bfbd46..1991c652738 100644 --- a/extern/Eigen3/Eigen/src/Householder/BlockHouseholder.h +++ b/extern/Eigen3/Eigen/src/Householder/BlockHouseholder.h @@ -4,30 +4,17 @@ // Copyright (C) 2010 Vincent Lejeune // Copyright (C) 2010 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_BLOCK_HOUSEHOLDER_H #define EIGEN_BLOCK_HOUSEHOLDER_H // This file contains some helper function to deal with block householder reflectors +namespace Eigen { + namespace internal { /** \internal */ @@ -64,7 +51,7 @@ void apply_block_householder_on_the_left(MatrixType& mat, const VectorsType& vec Matrix T(nbVecs,nbVecs); make_block_householder_triangular_factor(T, vectors, hCoeffs); - const TriangularView& V(vectors); + const TriangularView& V(vectors); // A -= V T V^* A Matrix // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_HOUSEHOLDER_H #define EIGEN_HOUSEHOLDER_H +namespace Eigen { + namespace internal { template struct decrement_size { @@ -35,6 +22,22 @@ template struct decrement_size }; } +/** Computes the elementary reflector H such that: + * \f$ H *this = [ beta 0 ... 0]^T \f$ + * where the transformation H is: + * \f$ H = I - tau v v^*\f$ + * and the vector v is: + * \f$ v^T = [1 essential^T] \f$ + * + * The essential part of the vector \c v is stored in *this. + * + * On output: + * \param tau the scaling factor of the Householder transformation + * \param beta the result of H * \c *this + * + * \sa MatrixBase::makeHouseholder(), MatrixBase::applyHouseholderOnTheLeft(), + * MatrixBase::applyHouseholderOnTheRight() + */ template void MatrixBase::makeHouseholderInPlace(Scalar& tau, RealScalar& beta) { @@ -51,7 +54,7 @@ void MatrixBase::makeHouseholderInPlace(Scalar& tau, RealScalar& beta) * * On output: * \param essential the essential part of the vector \c v - * \param tau the scaling factor of the householder transformation + * \param tau the scaling factor of the Householder transformation * \param beta the result of H * \c *this * * \sa MatrixBase::makeHouseholderInPlace(), MatrixBase::applyHouseholderOnTheLeft(), @@ -86,6 +89,21 @@ void MatrixBase::makeHouseholder( } } +/** Apply the elementary reflector H given by + * \f$ H = I - tau v v^*\f$ + * with + * \f$ v^T = [1 essential^T] \f$ + * from the left to a vector or matrix. + * + * On input: + * \param essential the essential part of the vector \c v + * \param tau the scaling factor of the Householder transformation + * \param workspace a pointer to working space with at least + * this->cols() * essential.size() entries + * + * \sa MatrixBase::makeHouseholder(), MatrixBase::makeHouseholderInPlace(), + * MatrixBase::applyHouseholderOnTheRight() + */ template template void MatrixBase::applyHouseholderOnTheLeft( @@ -108,6 +126,21 @@ void MatrixBase::applyHouseholderOnTheLeft( } } +/** Apply the elementary reflector H given by + * \f$ H = I - tau v v^*\f$ + * with + * \f$ v^T = [1 essential^T] \f$ + * from the right to a vector or matrix. + * + * On input: + * \param essential the essential part of the vector \c v + * \param tau the scaling factor of the Householder transformation + * \param workspace a pointer to working space with at least + * this->cols() * essential.size() entries + * + * \sa MatrixBase::makeHouseholder(), MatrixBase::makeHouseholderInPlace(), + * MatrixBase::applyHouseholderOnTheLeft() + */ template template void MatrixBase::applyHouseholderOnTheRight( @@ -130,4 +163,6 @@ void MatrixBase::applyHouseholderOnTheRight( } } +} // end namespace Eigen + #endif // EIGEN_HOUSEHOLDER_H diff --git a/extern/Eigen3/Eigen/src/Householder/HouseholderSequence.h b/extern/Eigen3/Eigen/src/Householder/HouseholderSequence.h index 717f29c99e9..1e71e16a785 100644 --- a/extern/Eigen3/Eigen/src/Householder/HouseholderSequence.h +++ b/extern/Eigen3/Eigen/src/Householder/HouseholderSequence.h @@ -4,28 +4,15 @@ // Copyright (C) 2009 Gael Guennebaud // Copyright (C) 2010 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_HOUSEHOLDER_SEQUENCE_H #define EIGEN_HOUSEHOLDER_SEQUENCE_H +namespace Eigen { + /** \ingroup Householder_Module * \householder_module * \class HouseholderSequence @@ -237,13 +224,20 @@ template class HouseholderS ConjugateReturnType inverse() const { return adjoint(); } /** \internal */ - template void evalTo(DestType& dst) const + template inline void evalTo(DestType& dst) const { - Index vecs = m_length; - // FIXME find a way to pass this temporary if the user wants to Matrix temp(rows()); - if( internal::is_same::type,DestType>::value + AutoAlign|ColMajor, DestType::MaxRowsAtCompileTime, 1> workspace(rows()); + evalTo(dst, workspace); + } + + /** \internal */ + template + void evalTo(Dest& dst, Workspace& workspace) const + { + workspace.resize(rows()); + Index vecs = m_length; + if( internal::is_same::type,Dest>::value && internal::extract_data(dst) == internal::extract_data(m_vectors)) { // in-place @@ -254,10 +248,10 @@ template class HouseholderS Index cornerSize = rows() - k - m_shift; if(m_trans) dst.bottomRightCorner(cornerSize, cornerSize) - .applyHouseholderOnTheRight(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); + .applyHouseholderOnTheRight(essentialVector(k), m_coeffs.coeff(k), workspace.data()); else dst.bottomRightCorner(cornerSize, cornerSize) - .applyHouseholderOnTheLeft(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); + .applyHouseholderOnTheLeft(essentialVector(k), m_coeffs.coeff(k), workspace.data()); // clear the off diagonal vector dst.col(k).tail(rows()-k-1).setZero(); @@ -274,10 +268,10 @@ template class HouseholderS Index cornerSize = rows() - k - m_shift; if(m_trans) dst.bottomRightCorner(cornerSize, cornerSize) - .applyHouseholderOnTheRight(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); + .applyHouseholderOnTheRight(essentialVector(k), m_coeffs.coeff(k), &workspace.coeffRef(0)); else dst.bottomRightCorner(cornerSize, cornerSize) - .applyHouseholderOnTheLeft(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); + .applyHouseholderOnTheLeft(essentialVector(k), m_coeffs.coeff(k), &workspace.coeffRef(0)); } } } @@ -285,24 +279,40 @@ template class HouseholderS /** \internal */ template inline void applyThisOnTheRight(Dest& dst) const { - Matrix temp(dst.rows()); + Matrix workspace(dst.rows()); + applyThisOnTheRight(dst, workspace); + } + + /** \internal */ + template + inline void applyThisOnTheRight(Dest& dst, Workspace& workspace) const + { + workspace.resize(dst.rows()); for(Index k = 0; k < m_length; ++k) { Index actual_k = m_trans ? m_length-k-1 : k; dst.rightCols(rows()-m_shift-actual_k) - .applyHouseholderOnTheRight(essentialVector(actual_k), m_coeffs.coeff(actual_k), &temp.coeffRef(0)); + .applyHouseholderOnTheRight(essentialVector(actual_k), m_coeffs.coeff(actual_k), workspace.data()); } } /** \internal */ template inline void applyThisOnTheLeft(Dest& dst) const { - Matrix temp(dst.cols()); + Matrix workspace(dst.cols()); + applyThisOnTheLeft(dst, workspace); + } + + /** \internal */ + template + inline void applyThisOnTheLeft(Dest& dst, Workspace& workspace) const + { + workspace.resize(dst.cols()); for(Index k = 0; k < m_length; ++k) { Index actual_k = m_trans ? k : m_length-k-1; dst.bottomRows(rows()-m_shift-actual_k) - .applyHouseholderOnTheLeft(essentialVector(actual_k), m_coeffs.coeff(actual_k), &temp.coeffRef(0)); + .applyHouseholderOnTheLeft(essentialVector(actual_k), m_coeffs.coeff(actual_k), workspace.data()); } } @@ -426,4 +436,6 @@ HouseholderSequence rightHouseholderSequence( return HouseholderSequence(v, h); } +} // end namespace Eigen + #endif // EIGEN_HOUSEHOLDER_SEQUENCE_H diff --git a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h new file mode 100644 index 00000000000..73ca9bfde6a --- /dev/null +++ b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h @@ -0,0 +1,149 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_BASIC_PRECONDITIONERS_H +#define EIGEN_BASIC_PRECONDITIONERS_H + +namespace Eigen { + +/** \ingroup IterativeLinearSolvers_Module + * \brief A preconditioner based on the digonal entries + * + * This class allows to approximately solve for A.x = b problems assuming A is a diagonal matrix. + * In other words, this preconditioner neglects all off diagonal entries and, in Eigen's language, solves for: + * \code + * A.diagonal().asDiagonal() . x = b + * \endcode + * + * \tparam _Scalar the type of the scalar. + * + * This preconditioner is suitable for both selfadjoint and general problems. + * The diagonal entries are pre-inverted and stored into a dense vector. + * + * \note A variant that has yet to be implemented would attempt to preserve the norm of each column. + * + */ +template +class DiagonalPreconditioner +{ + typedef _Scalar Scalar; + typedef Matrix Vector; + typedef typename Vector::Index Index; + + public: + // this typedef is only to export the scalar type and compile-time dimensions to solve_retval + typedef Matrix MatrixType; + + DiagonalPreconditioner() : m_isInitialized(false) {} + + template + DiagonalPreconditioner(const MatType& mat) : m_invdiag(mat.cols()) + { + compute(mat); + } + + Index rows() const { return m_invdiag.size(); } + Index cols() const { return m_invdiag.size(); } + + template + DiagonalPreconditioner& analyzePattern(const MatType& ) + { + return *this; + } + + template + DiagonalPreconditioner& factorize(const MatType& mat) + { + m_invdiag.resize(mat.cols()); + for(int j=0; j + DiagonalPreconditioner& compute(const MatType& mat) + { + return factorize(mat); + } + + template + void _solve(const Rhs& b, Dest& x) const + { + x = m_invdiag.array() * b.array() ; + } + + template inline const internal::solve_retval + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "DiagonalPreconditioner is not initialized."); + eigen_assert(m_invdiag.size()==b.rows() + && "DiagonalPreconditioner::solve(): invalid number of rows of the right hand side matrix b"); + return internal::solve_retval(*this, b.derived()); + } + + protected: + Vector m_invdiag; + bool m_isInitialized; +}; + +namespace internal { + +template +struct solve_retval, Rhs> + : solve_retval_base, Rhs> +{ + typedef DiagonalPreconditioner<_MatrixType> Dec; + EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec()._solve(rhs(),dst); + } +}; + +} + +/** \ingroup IterativeLinearSolvers_Module + * \brief A naive preconditioner which approximates any matrix as the identity matrix + * + * \sa class DiagonalPreconditioner + */ +class IdentityPreconditioner +{ + public: + + IdentityPreconditioner() {} + + template + IdentityPreconditioner(const MatrixType& ) {} + + template + IdentityPreconditioner& analyzePattern(const MatrixType& ) { return *this; } + + template + IdentityPreconditioner& factorize(const MatrixType& ) { return *this; } + + template + IdentityPreconditioner& compute(const MatrixType& ) { return *this; } + + template + inline const Rhs& solve(const Rhs& b) const { return b; } +}; + +} // end namespace Eigen + +#endif // EIGEN_BASIC_PRECONDITIONERS_H diff --git a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h new file mode 100644 index 00000000000..126341be8d8 --- /dev/null +++ b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h @@ -0,0 +1,254 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Gael Guennebaud +// Copyright (C) 2012 Désiré Nuentsa-Wakam +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_BICGSTAB_H +#define EIGEN_BICGSTAB_H + +namespace Eigen { + +namespace internal { + +/** \internal Low-level bi conjugate gradient stabilized algorithm + * \param mat The matrix A + * \param rhs The right hand side vector b + * \param x On input and initial solution, on output the computed solution. + * \param precond A preconditioner being able to efficiently solve for an + * approximation of Ax=b (regardless of b) + * \param iters On input the max number of iteration, on output the number of performed iterations. + * \param tol_error On input the tolerance error, on output an estimation of the relative error. + * \return false in the case of numerical issue, for example a break down of BiCGSTAB. + */ +template +bool bicgstab(const MatrixType& mat, const Rhs& rhs, Dest& x, + const Preconditioner& precond, int& iters, + typename Dest::RealScalar& tol_error) +{ + using std::sqrt; + using std::abs; + typedef typename Dest::RealScalar RealScalar; + typedef typename Dest::Scalar Scalar; + typedef Matrix VectorType; + RealScalar tol = tol_error; + int maxIters = iters; + + int n = mat.cols(); + VectorType r = rhs - mat * x; + VectorType r0 = r; + + RealScalar r0_sqnorm = r0.squaredNorm(); + Scalar rho = 1; + Scalar alpha = 1; + Scalar w = 1; + + VectorType v = VectorType::Zero(n), p = VectorType::Zero(n); + VectorType y(n), z(n); + VectorType kt(n), ks(n); + + VectorType s(n), t(n); + + RealScalar tol2 = tol*tol; + int i = 0; + + while ( r.squaredNorm()/r0_sqnorm > tol2 && i > +class BiCGSTAB; + +namespace internal { + +template< typename _MatrixType, typename _Preconditioner> +struct traits > +{ + typedef _MatrixType MatrixType; + typedef _Preconditioner Preconditioner; +}; + +} + +/** \ingroup IterativeLinearSolvers_Module + * \brief A bi conjugate gradient stabilized solver for sparse square problems + * + * This class allows to solve for A.x = b sparse linear problems using a bi conjugate gradient + * stabilized algorithm. The vectors x and b can be either dense or sparse. + * + * \tparam _MatrixType the type of the sparse matrix A, can be a dense or a sparse matrix. + * \tparam _Preconditioner the type of the preconditioner. Default is DiagonalPreconditioner + * + * The maximal number of iterations and tolerance value can be controlled via the setMaxIterations() + * and setTolerance() methods. The defaults are the size of the problem for the maximal number of iterations + * and NumTraits::epsilon() for the tolerance. + * + * This class can be used as the direct solver classes. Here is a typical usage example: + * \code + * int n = 10000; + * VectorXd x(n), b(n); + * SparseMatrix A(n,n); + * // fill A and b + * BiCGSTAB > solver; + * solver(A); + * x = solver.solve(b); + * std::cout << "#iterations: " << solver.iterations() << std::endl; + * std::cout << "estimated error: " << solver.error() << std::endl; + * // update b, and solve again + * x = solver.solve(b); + * \endcode + * + * By default the iterations start with x=0 as an initial guess of the solution. + * One can control the start using the solveWithGuess() method. Here is a step by + * step execution example starting with a random guess and printing the evolution + * of the estimated error: + * * \code + * x = VectorXd::Random(n); + * solver.setMaxIterations(1); + * int i = 0; + * do { + * x = solver.solveWithGuess(b,x); + * std::cout << i << " : " << solver.error() << std::endl; + * ++i; + * } while (solver.info()!=Success && i<100); + * \endcode + * Note that such a step by step excution is slightly slower. + * + * \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner + */ +template< typename _MatrixType, typename _Preconditioner> +class BiCGSTAB : public IterativeSolverBase > +{ + typedef IterativeSolverBase Base; + using Base::mp_matrix; + using Base::m_error; + using Base::m_iterations; + using Base::m_info; + using Base::m_isInitialized; +public: + typedef _MatrixType MatrixType; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::Index Index; + typedef typename MatrixType::RealScalar RealScalar; + typedef _Preconditioner Preconditioner; + +public: + + /** Default constructor. */ + BiCGSTAB() : Base() {} + + /** Initialize the solver with matrix \a A for further \c Ax=b solving. + * + * This constructor is a shortcut for the default constructor followed + * by a call to compute(). + * + * \warning this class stores a reference to the matrix A as well as some + * precomputed values that depend on it. Therefore, if \a A is changed + * this class becomes invalid. Call compute() to update it with the new + * matrix A, or modify a copy of A. + */ + BiCGSTAB(const MatrixType& A) : Base(A) {} + + ~BiCGSTAB() {} + + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A + * \a x0 as an initial solution. + * + * \sa compute() + */ + template + inline const internal::solve_retval_with_guess + solveWithGuess(const MatrixBase& b, const Guess& x0) const + { + eigen_assert(m_isInitialized && "BiCGSTAB is not initialized."); + eigen_assert(Base::rows()==b.rows() + && "BiCGSTAB::solve(): invalid number of rows of the right hand side matrix b"); + return internal::solve_retval_with_guess + (*this, b.derived(), x0); + } + + /** \internal */ + template + void _solveWithGuess(const Rhs& b, Dest& x) const + { + bool failed = false; + for(int j=0; j + void _solve(const Rhs& b, Dest& x) const + { + x.setZero(); + _solveWithGuess(b,x); + } + +protected: + +}; + + +namespace internal { + + template +struct solve_retval, Rhs> + : solve_retval_base, Rhs> +{ + typedef BiCGSTAB<_MatrixType, _Preconditioner> Dec; + EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec()._solve(rhs(),dst); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_BICGSTAB_H diff --git a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h new file mode 100644 index 00000000000..f64f2534d28 --- /dev/null +++ b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h @@ -0,0 +1,251 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CONJUGATE_GRADIENT_H +#define EIGEN_CONJUGATE_GRADIENT_H + +namespace Eigen { + +namespace internal { + +/** \internal Low-level conjugate gradient algorithm + * \param mat The matrix A + * \param rhs The right hand side vector b + * \param x On input and initial solution, on output the computed solution. + * \param precond A preconditioner being able to efficiently solve for an + * approximation of Ax=b (regardless of b) + * \param iters On input the max number of iteration, on output the number of performed iterations. + * \param tol_error On input the tolerance error, on output an estimation of the relative error. + */ +template +EIGEN_DONT_INLINE +void conjugate_gradient(const MatrixType& mat, const Rhs& rhs, Dest& x, + const Preconditioner& precond, int& iters, + typename Dest::RealScalar& tol_error) +{ + using std::sqrt; + using std::abs; + typedef typename Dest::RealScalar RealScalar; + typedef typename Dest::Scalar Scalar; + typedef Matrix VectorType; + + RealScalar tol = tol_error; + int maxIters = iters; + + int n = mat.cols(); + + VectorType residual = rhs - mat * x; //initial residual + VectorType p(n); + + p = precond.solve(residual); //initial search direction + + VectorType z(n), tmp(n); + RealScalar absNew = internal::real(residual.dot(p)); // the square of the absolute value of r scaled by invM + RealScalar rhsNorm2 = rhs.squaredNorm(); + RealScalar residualNorm2 = 0; + RealScalar threshold = tol*tol*rhsNorm2; + int i = 0; + while(i < maxIters) + { + tmp.noalias() = mat * p; // the bottleneck of the algorithm + + Scalar alpha = absNew / p.dot(tmp); // the amount we travel on dir + x += alpha * p; // update solution + residual -= alpha * tmp; // update residue + + residualNorm2 = residual.squaredNorm(); + if(residualNorm2 < threshold) + break; + + z = precond.solve(residual); // approximately solve for "A z = residual" + + RealScalar absOld = absNew; + absNew = internal::real(residual.dot(z)); // update the absolute value of r + RealScalar beta = absNew / absOld; // calculate the Gram-Schmidt value used to create the new search direction + p = z + beta * p; // update search direction + i++; + } + tol_error = sqrt(residualNorm2 / rhsNorm2); + iters = i; +} + +} + +template< typename _MatrixType, int _UpLo=Lower, + typename _Preconditioner = DiagonalPreconditioner > +class ConjugateGradient; + +namespace internal { + +template< typename _MatrixType, int _UpLo, typename _Preconditioner> +struct traits > +{ + typedef _MatrixType MatrixType; + typedef _Preconditioner Preconditioner; +}; + +} + +/** \ingroup IterativeLinearSolvers_Module + * \brief A conjugate gradient solver for sparse self-adjoint problems + * + * This class allows to solve for A.x = b sparse linear problems using a conjugate gradient algorithm. + * The sparse matrix A must be selfadjoint. The vectors x and b can be either dense or sparse. + * + * \tparam _MatrixType the type of the sparse matrix A, can be a dense or a sparse matrix. + * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower + * or Upper. Default is Lower. + * \tparam _Preconditioner the type of the preconditioner. Default is DiagonalPreconditioner + * + * The maximal number of iterations and tolerance value can be controlled via the setMaxIterations() + * and setTolerance() methods. The defaults are the size of the problem for the maximal number of iterations + * and NumTraits::epsilon() for the tolerance. + * + * This class can be used as the direct solver classes. Here is a typical usage example: + * \code + * int n = 10000; + * VectorXd x(n), b(n); + * SparseMatrix A(n,n); + * // fill A and b + * ConjugateGradient > cg; + * cg.compute(A); + * x = cg.solve(b); + * std::cout << "#iterations: " << cg.iterations() << std::endl; + * std::cout << "estimated error: " << cg.error() << std::endl; + * // update b, and solve again + * x = cg.solve(b); + * \endcode + * + * By default the iterations start with x=0 as an initial guess of the solution. + * One can control the start using the solveWithGuess() method. Here is a step by + * step execution example starting with a random guess and printing the evolution + * of the estimated error: + * * \code + * x = VectorXd::Random(n); + * cg.setMaxIterations(1); + * int i = 0; + * do { + * x = cg.solveWithGuess(b,x); + * std::cout << i << " : " << cg.error() << std::endl; + * ++i; + * } while (cg.info()!=Success && i<100); + * \endcode + * Note that such a step by step excution is slightly slower. + * + * \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner + */ +template< typename _MatrixType, int _UpLo, typename _Preconditioner> +class ConjugateGradient : public IterativeSolverBase > +{ + typedef IterativeSolverBase Base; + using Base::mp_matrix; + using Base::m_error; + using Base::m_iterations; + using Base::m_info; + using Base::m_isInitialized; +public: + typedef _MatrixType MatrixType; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::Index Index; + typedef typename MatrixType::RealScalar RealScalar; + typedef _Preconditioner Preconditioner; + + enum { + UpLo = _UpLo + }; + +public: + + /** Default constructor. */ + ConjugateGradient() : Base() {} + + /** Initialize the solver with matrix \a A for further \c Ax=b solving. + * + * This constructor is a shortcut for the default constructor followed + * by a call to compute(). + * + * \warning this class stores a reference to the matrix A as well as some + * precomputed values that depend on it. Therefore, if \a A is changed + * this class becomes invalid. Call compute() to update it with the new + * matrix A, or modify a copy of A. + */ + ConjugateGradient(const MatrixType& A) : Base(A) {} + + ~ConjugateGradient() {} + + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A + * \a x0 as an initial solution. + * + * \sa compute() + */ + template + inline const internal::solve_retval_with_guess + solveWithGuess(const MatrixBase& b, const Guess& x0) const + { + eigen_assert(m_isInitialized && "ConjugateGradient is not initialized."); + eigen_assert(Base::rows()==b.rows() + && "ConjugateGradient::solve(): invalid number of rows of the right hand side matrix b"); + return internal::solve_retval_with_guess + (*this, b.derived(), x0); + } + + /** \internal */ + template + void _solveWithGuess(const Rhs& b, Dest& x) const + { + m_iterations = Base::maxIterations(); + m_error = Base::m_tolerance; + + for(int j=0; jtemplate selfadjointView(), b.col(j), xj, + Base::m_preconditioner, m_iterations, m_error); + } + + m_isInitialized = true; + m_info = m_error <= Base::m_tolerance ? Success : NoConvergence; + } + + /** \internal */ + template + void _solve(const Rhs& b, Dest& x) const + { + x.setOnes(); + _solveWithGuess(b,x); + } + +protected: + +}; + + +namespace internal { + +template +struct solve_retval, Rhs> + : solve_retval_base, Rhs> +{ + typedef ConjugateGradient<_MatrixType,_UpLo,_Preconditioner> Dec; + EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec()._solve(rhs(),dst); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_CONJUGATE_GRADIENT_H diff --git a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h new file mode 100644 index 00000000000..224304f0eb8 --- /dev/null +++ b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h @@ -0,0 +1,466 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2012 Désiré Nuentsa-Wakam +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_INCOMPLETE_LUT_H +#define EIGEN_INCOMPLETE_LUT_H + +namespace Eigen { + +/** + * \brief Incomplete LU factorization with dual-threshold strategy + * During the numerical factorization, two dropping rules are used : + * 1) any element whose magnitude is less than some tolerance is dropped. + * This tolerance is obtained by multiplying the input tolerance @p droptol + * by the average magnitude of all the original elements in the current row. + * 2) After the elimination of the row, only the @p fill largest elements in + * the L part and the @p fill largest elements in the U part are kept + * (in addition to the diagonal element ). Note that @p fill is computed from + * the input parameter @p fillfactor which is used the ratio to control the fill_in + * relatively to the initial number of nonzero elements. + * + * The two extreme cases are when @p droptol=0 (to keep all the @p fill*2 largest elements) + * and when @p fill=n/2 with @p droptol being different to zero. + * + * References : Yousef Saad, ILUT: A dual threshold incomplete LU factorization, + * Numerical Linear Algebra with Applications, 1(4), pp 387-402, 1994. + * + * NOTE : The following implementation is derived from the ILUT implementation + * in the SPARSKIT package, Copyright (C) 2005, the Regents of the University of Minnesota + * released under the terms of the GNU LGPL: + * http://www-users.cs.umn.edu/~saad/software/SPARSKIT/README + * However, Yousef Saad gave us permission to relicense his ILUT code to MPL2. + * See the Eigen mailing list archive, thread: ILUT, date: July 8, 2012: + * http://listengine.tuxfamily.org/lists.tuxfamily.org/eigen/2012/07/msg00064.html + * alternatively, on GMANE: + * http://comments.gmane.org/gmane.comp.lib.eigen/3302 + */ +template +class IncompleteLUT : internal::noncopyable +{ + typedef _Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + typedef Matrix Vector; + typedef SparseMatrix FactorType; + typedef SparseMatrix PermutType; + typedef typename FactorType::Index Index; + + public: + typedef Matrix MatrixType; + + IncompleteLUT() + : m_droptol(NumTraits::dummy_precision()), m_fillfactor(10), + m_analysisIsOk(false), m_factorizationIsOk(false), m_isInitialized(false) + {} + + template + IncompleteLUT(const MatrixType& mat, RealScalar droptol=NumTraits::dummy_precision(), int fillfactor = 10) + : m_droptol(droptol),m_fillfactor(fillfactor), + m_analysisIsOk(false),m_factorizationIsOk(false),m_isInitialized(false) + { + eigen_assert(fillfactor != 0); + compute(mat); + } + + Index rows() const { return m_lu.rows(); } + + Index cols() const { return m_lu.cols(); } + + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was succesful, + * \c NumericalIssue if the matrix.appears to be negative. + */ + ComputationInfo info() const + { + eigen_assert(m_isInitialized && "IncompleteLUT is not initialized."); + return m_info; + } + + template + void analyzePattern(const MatrixType& amat); + + template + void factorize(const MatrixType& amat); + + /** + * Compute an incomplete LU factorization with dual threshold on the matrix mat + * No pivoting is done in this version + * + **/ + template + IncompleteLUT& compute(const MatrixType& amat) + { + analyzePattern(amat); + factorize(amat); + eigen_assert(m_factorizationIsOk == true); + m_isInitialized = true; + return *this; + } + + void setDroptol(RealScalar droptol); + void setFillfactor(int fillfactor); + + template + void _solve(const Rhs& b, Dest& x) const + { + x = m_Pinv * b; + x = m_lu.template triangularView().solve(x); + x = m_lu.template triangularView().solve(x); + x = m_P * x; + } + + template inline const internal::solve_retval + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "IncompleteLUT is not initialized."); + eigen_assert(cols()==b.rows() + && "IncompleteLUT::solve(): invalid number of rows of the right hand side matrix b"); + return internal::solve_retval(*this, b.derived()); + } + +protected: + + template + int QuickSplit(VectorV &row, VectorI &ind, int ncut); + + + /** keeps off-diagonal entries; drops diagonal entries */ + struct keep_diag { + inline bool operator() (const Index& row, const Index& col, const Scalar&) const + { + return row!=col; + } + }; + +protected: + + FactorType m_lu; + RealScalar m_droptol; + int m_fillfactor; + bool m_analysisIsOk; + bool m_factorizationIsOk; + bool m_isInitialized; + ComputationInfo m_info; + PermutationMatrix m_P; // Fill-reducing permutation + PermutationMatrix m_Pinv; // Inverse permutation +}; + +/** + * Set control parameter droptol + * \param droptol Drop any element whose magnitude is less than this tolerance + **/ +template +void IncompleteLUT::setDroptol(RealScalar droptol) +{ + this->m_droptol = droptol; +} + +/** + * Set control parameter fillfactor + * \param fillfactor This is used to compute the number @p fill_in of largest elements to keep on each row. + **/ +template +void IncompleteLUT::setFillfactor(int fillfactor) +{ + this->m_fillfactor = fillfactor; +} + + +/** + * Compute a quick-sort split of a vector + * On output, the vector row is permuted such that its elements satisfy + * abs(row(i)) >= abs(row(ncut)) if incut + * \param row The vector of values + * \param ind The array of index for the elements in @p row + * \param ncut The number of largest elements to keep + **/ +template +template +int IncompleteLUT::QuickSplit(VectorV &row, VectorI &ind, int ncut) +{ + using std::swap; + int mid; + int n = row.size(); /* length of the vector */ + int first, last ; + + ncut--; /* to fit the zero-based indices */ + first = 0; + last = n-1; + if (ncut < first || ncut > last ) return 0; + + do { + mid = first; + RealScalar abskey = std::abs(row(mid)); + for (int j = first + 1; j <= last; j++) { + if ( std::abs(row(j)) > abskey) { + ++mid; + swap(row(mid), row(j)); + swap(ind(mid), ind(j)); + } + } + /* Interchange for the pivot element */ + swap(row(mid), row(first)); + swap(ind(mid), ind(first)); + + if (mid > ncut) last = mid - 1; + else if (mid < ncut ) first = mid + 1; + } while (mid != ncut ); + + return 0; /* mid is equal to ncut */ +} + +template +template +void IncompleteLUT::analyzePattern(const _MatrixType& amat) +{ + // Compute the Fill-reducing permutation + SparseMatrix mat1 = amat; + SparseMatrix mat2 = amat.transpose(); + // Symmetrize the pattern + // FIXME for a matrix with nearly symmetric pattern, mat2+mat1 is the appropriate choice. + // on the other hand for a really non-symmetric pattern, mat2*mat1 should be prefered... + SparseMatrix AtA = mat2 + mat1; + AtA.prune(keep_diag()); + internal::minimum_degree_ordering(AtA, m_P); // Then compute the AMD ordering... + + m_Pinv = m_P.inverse(); // ... and the inverse permutation + + m_analysisIsOk = true; +} + +template +template +void IncompleteLUT::factorize(const _MatrixType& amat) +{ + using std::sqrt; + using std::swap; + using std::abs; + + eigen_assert((amat.rows() == amat.cols()) && "The factorization should be done on a square matrix"); + int n = amat.cols(); // Size of the matrix + m_lu.resize(n,n); + // Declare Working vectors and variables + Vector u(n) ; // real values of the row -- maximum size is n -- + VectorXi ju(n); // column position of the values in u -- maximum size is n + VectorXi jr(n); // Indicate the position of the nonzero elements in the vector u -- A zero location is indicated by -1 + + // Apply the fill-reducing permutation + eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); + SparseMatrix mat; + mat = amat.twistedBy(m_Pinv); + + // Initialization + jr.fill(-1); + ju.fill(0); + u.fill(0); + + // number of largest elements to keep in each row: + int fill_in = static_cast (amat.nonZeros()*m_fillfactor)/n+1; + if (fill_in > n) fill_in = n; + + // number of largest nonzero elements to keep in the L and the U part of the current row: + int nnzL = fill_in/2; + int nnzU = nnzL; + m_lu.reserve(n * (nnzL + nnzU + 1)); + + // global loop over the rows of the sparse matrix + for (int ii = 0; ii < n; ii++) + { + // 1 - copy the lower and the upper part of the row i of mat in the working vector u + + int sizeu = 1; // number of nonzero elements in the upper part of the current row + int sizel = 0; // number of nonzero elements in the lower part of the current row + ju(ii) = ii; + u(ii) = 0; + jr(ii) = ii; + RealScalar rownorm = 0; + + typename FactorType::InnerIterator j_it(mat, ii); // Iterate through the current row ii + for (; j_it; ++j_it) + { + int k = j_it.index(); + if (k < ii) + { + // copy the lower part + ju(sizel) = k; + u(sizel) = j_it.value(); + jr(k) = sizel; + ++sizel; + } + else if (k == ii) + { + u(ii) = j_it.value(); + } + else + { + // copy the upper part + int jpos = ii + sizeu; + ju(jpos) = k; + u(jpos) = j_it.value(); + jr(k) = jpos; + ++sizeu; + } + rownorm += internal::abs2(j_it.value()); + } + + // 2 - detect possible zero row + if(rownorm==0) + { + m_info = NumericalIssue; + return; + } + // Take the 2-norm of the current row as a relative tolerance + rownorm = sqrt(rownorm); + + // 3 - eliminate the previous nonzero rows + int jj = 0; + int len = 0; + while (jj < sizel) + { + // In order to eliminate in the correct order, + // we must select first the smallest column index among ju(jj:sizel) + int k; + int minrow = ju.segment(jj,sizel-jj).minCoeff(&k); // k is relative to the segment + k += jj; + if (minrow != ju(jj)) + { + // swap the two locations + int j = ju(jj); + swap(ju(jj), ju(k)); + jr(minrow) = jj; jr(j) = k; + swap(u(jj), u(k)); + } + // Reset this location + jr(minrow) = -1; + + // Start elimination + typename FactorType::InnerIterator ki_it(m_lu, minrow); + while (ki_it && ki_it.index() < minrow) ++ki_it; + eigen_internal_assert(ki_it && ki_it.col()==minrow); + Scalar fact = u(jj) / ki_it.value(); + + // drop too small elements + if(abs(fact) <= m_droptol) + { + jj++; + continue; + } + + // linear combination of the current row ii and the row minrow + ++ki_it; + for (; ki_it; ++ki_it) + { + Scalar prod = fact * ki_it.value(); + int j = ki_it.index(); + int jpos = jr(j); + if (jpos == -1) // fill-in element + { + int newpos; + if (j >= ii) // dealing with the upper part + { + newpos = ii + sizeu; + sizeu++; + eigen_internal_assert(sizeu<=n); + } + else // dealing with the lower part + { + newpos = sizel; + sizel++; + eigen_internal_assert(sizel<=ii); + } + ju(newpos) = j; + u(newpos) = -prod; + jr(j) = newpos; + } + else + u(jpos) -= prod; + } + // store the pivot element + u(len) = fact; + ju(len) = minrow; + ++len; + + jj++; + } // end of the elimination on the row ii + + // reset the upper part of the pointer jr to zero + for(int k = 0; k m_droptol * rownorm ) + { + ++len; + u(ii + len) = u(ii + k); + ju(ii + len) = ju(ii + k); + } + } + sizeu = len + 1; // +1 to take into account the diagonal element + len = (std::min)(sizeu, nnzU); + typename Vector::SegmentReturnType uu(u.segment(ii+1, sizeu-1)); + typename VectorXi::SegmentReturnType juu(ju.segment(ii+1, sizeu-1)); + QuickSplit(uu, juu, len); + + // store the largest elements of the U part + for(int k = ii + 1; k < ii + len; k++) + m_lu.insertBackByOuterInnerUnordered(ii,ju(k)) = u(k); + } + + m_lu.finalize(); + m_lu.makeCompressed(); + + m_factorizationIsOk = true; + m_info = Success; +} + +namespace internal { + +template +struct solve_retval, Rhs> + : solve_retval_base, Rhs> +{ + typedef IncompleteLUT<_MatrixType> Dec; + EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec()._solve(rhs(),dst); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_INCOMPLETE_LUT_H + diff --git a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h new file mode 100644 index 00000000000..11706cebabd --- /dev/null +++ b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h @@ -0,0 +1,254 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ITERATIVE_SOLVER_BASE_H +#define EIGEN_ITERATIVE_SOLVER_BASE_H + +namespace Eigen { + +/** \ingroup IterativeLinearSolvers_Module + * \brief Base class for linear iterative solvers + * + * \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner + */ +template< typename Derived> +class IterativeSolverBase : internal::noncopyable +{ +public: + typedef typename internal::traits::MatrixType MatrixType; + typedef typename internal::traits::Preconditioner Preconditioner; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::Index Index; + typedef typename MatrixType::RealScalar RealScalar; + +public: + + Derived& derived() { return *static_cast(this); } + const Derived& derived() const { return *static_cast(this); } + + /** Default constructor. */ + IterativeSolverBase() + : mp_matrix(0) + { + init(); + } + + /** Initialize the solver with matrix \a A for further \c Ax=b solving. + * + * This constructor is a shortcut for the default constructor followed + * by a call to compute(). + * + * \warning this class stores a reference to the matrix A as well as some + * precomputed values that depend on it. Therefore, if \a A is changed + * this class becomes invalid. Call compute() to update it with the new + * matrix A, or modify a copy of A. + */ + IterativeSolverBase(const MatrixType& A) + { + init(); + compute(A); + } + + ~IterativeSolverBase() {} + + /** Initializes the iterative solver for the sparcity pattern of the matrix \a A for further solving \c Ax=b problems. + * + * Currently, this function mostly call analyzePattern on the preconditioner. In the future + * we might, for instance, implement column reodering for faster matrix vector products. + */ + Derived& analyzePattern(const MatrixType& A) + { + m_preconditioner.analyzePattern(A); + m_isInitialized = true; + m_analysisIsOk = true; + m_info = Success; + return derived(); + } + + /** Initializes the iterative solver with the numerical values of the matrix \a A for further solving \c Ax=b problems. + * + * Currently, this function mostly call factorize on the preconditioner. + * + * \warning this class stores a reference to the matrix A as well as some + * precomputed values that depend on it. Therefore, if \a A is changed + * this class becomes invalid. Call compute() to update it with the new + * matrix A, or modify a copy of A. + */ + Derived& factorize(const MatrixType& A) + { + eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); + mp_matrix = &A; + m_preconditioner.factorize(A); + m_factorizationIsOk = true; + m_info = Success; + return derived(); + } + + /** Initializes the iterative solver with the matrix \a A for further solving \c Ax=b problems. + * + * Currently, this function mostly initialized/compute the preconditioner. In the future + * we might, for instance, implement column reodering for faster matrix vector products. + * + * \warning this class stores a reference to the matrix A as well as some + * precomputed values that depend on it. Therefore, if \a A is changed + * this class becomes invalid. Call compute() to update it with the new + * matrix A, or modify a copy of A. + */ + Derived& compute(const MatrixType& A) + { + mp_matrix = &A; + m_preconditioner.compute(A); + m_isInitialized = true; + m_analysisIsOk = true; + m_factorizationIsOk = true; + m_info = Success; + return derived(); + } + + /** \internal */ + Index rows() const { return mp_matrix ? mp_matrix->rows() : 0; } + /** \internal */ + Index cols() const { return mp_matrix ? mp_matrix->cols() : 0; } + + /** \returns the tolerance threshold used by the stopping criteria */ + RealScalar tolerance() const { return m_tolerance; } + + /** Sets the tolerance threshold used by the stopping criteria */ + Derived& setTolerance(RealScalar tolerance) + { + m_tolerance = tolerance; + return derived(); + } + + /** \returns a read-write reference to the preconditioner for custom configuration. */ + Preconditioner& preconditioner() { return m_preconditioner; } + + /** \returns a read-only reference to the preconditioner. */ + const Preconditioner& preconditioner() const { return m_preconditioner; } + + /** \returns the max number of iterations */ + int maxIterations() const + { + return (mp_matrix && m_maxIterations<0) ? mp_matrix->cols() : m_maxIterations; + } + + /** Sets the max number of iterations */ + Derived& setMaxIterations(int maxIters) + { + m_maxIterations = maxIters; + return derived(); + } + + /** \returns the number of iterations performed during the last solve */ + int iterations() const + { + eigen_assert(m_isInitialized && "ConjugateGradient is not initialized."); + return m_iterations; + } + + /** \returns the tolerance error reached during the last solve */ + RealScalar error() const + { + eigen_assert(m_isInitialized && "ConjugateGradient is not initialized."); + return m_error; + } + + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ + template inline const internal::solve_retval + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "IterativeSolverBase is not initialized."); + eigen_assert(rows()==b.rows() + && "IterativeSolverBase::solve(): invalid number of rows of the right hand side matrix b"); + return internal::solve_retval(derived(), b.derived()); + } + + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ + template + inline const internal::sparse_solve_retval + solve(const SparseMatrixBase& b) const + { + eigen_assert(m_isInitialized && "IterativeSolverBase is not initialized."); + eigen_assert(rows()==b.rows() + && "IterativeSolverBase::solve(): invalid number of rows of the right hand side matrix b"); + return internal::sparse_solve_retval(*this, b.derived()); + } + + /** \returns Success if the iterations converged, and NoConvergence otherwise. */ + ComputationInfo info() const + { + eigen_assert(m_isInitialized && "IterativeSolverBase is not initialized."); + return m_info; + } + + /** \internal */ + template + void _solve_sparse(const Rhs& b, SparseMatrix &dest) const + { + eigen_assert(rows()==b.rows()); + + int rhsCols = b.cols(); + int size = b.rows(); + Eigen::Matrix tb(size); + Eigen::Matrix tx(size); + for(int k=0; k::epsilon(); + } + const MatrixType* mp_matrix; + Preconditioner m_preconditioner; + + int m_maxIterations; + RealScalar m_tolerance; + + mutable RealScalar m_error; + mutable int m_iterations; + mutable ComputationInfo m_info; + mutable bool m_isInitialized, m_analysisIsOk, m_factorizationIsOk; +}; + +namespace internal { + +template +struct sparse_solve_retval, Rhs> + : sparse_solve_retval_base, Rhs> +{ + typedef IterativeSolverBase Dec; + EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec().derived()._solve_sparse(rhs(),dst); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_ITERATIVE_SOLVER_BASE_H diff --git a/extern/Eigen3/Eigen/src/Jacobi/Jacobi.h b/extern/Eigen3/Eigen/src/Jacobi/Jacobi.h index 98dea6800bc..a9c17dcdf19 100644 --- a/extern/Eigen3/Eigen/src/Jacobi/Jacobi.h +++ b/extern/Eigen3/Eigen/src/Jacobi/Jacobi.h @@ -4,28 +4,15 @@ // Copyright (C) 2009 Benoit Jacob // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_JACOBI_H #define EIGEN_JACOBI_H +namespace Eigen { + /** \ingroup Jacobi_Module * \jacobi_module * \class JacobiRotation @@ -326,7 +313,7 @@ void /*EIGEN_DONT_INLINE*/ apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, // both vectors are sequentially stored in memory => vectorization enum { Peeling = 2 }; - Index alignedStart = first_aligned(y, size); + Index alignedStart = internal::first_aligned(y, size); Index alignedEnd = alignedStart + ((size-alignedStart)/PacketSize)*PacketSize; const Packet pc = pset1(j.c()); @@ -344,7 +331,7 @@ void /*EIGEN_DONT_INLINE*/ apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, Scalar* EIGEN_RESTRICT px = x + alignedStart; Scalar* EIGEN_RESTRICT py = y + alignedStart; - if(first_aligned(x, size)==alignedStart) + if(internal::first_aligned(x, size)==alignedStart) { for(Index i=alignedStart; i // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_DETERMINANT_H #define EIGEN_DETERMINANT_H +namespace Eigen { + namespace internal { template @@ -109,4 +96,6 @@ inline typename internal::traits::Scalar MatrixBase::determina return internal::determinant_impl::type>::run(derived()); } +} // end namespace Eigen + #endif // EIGEN_DETERMINANT_H diff --git a/extern/Eigen3/Eigen/src/LU/FullPivLU.h b/extern/Eigen3/Eigen/src/LU/FullPivLU.h index 46ae7d651c8..e23f96cdcf1 100644 --- a/extern/Eigen3/Eigen/src/LU/FullPivLU.h +++ b/extern/Eigen3/Eigen/src/LU/FullPivLU.h @@ -3,28 +3,15 @@ // // Copyright (C) 2006-2009 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_LU_H #define EIGEN_LU_H +namespace Eigen { + /** \ingroup LU_Module * * \class FullPivLU @@ -282,6 +269,7 @@ template class FullPivLU FullPivLU& setThreshold(Default_t) { m_usePrescribedThreshold = false; + return *this; } /** Returns the threshold that will be used by certain methods such as rank(). @@ -743,4 +731,6 @@ MatrixBase::fullPivLu() const return FullPivLU(eval()); } +} // end namespace Eigen + #endif // EIGEN_LU_H diff --git a/extern/Eigen3/Eigen/src/LU/Inverse.h b/extern/Eigen3/Eigen/src/LU/Inverse.h index 2d3e6d10529..39b8cdbc8dc 100644 --- a/extern/Eigen3/Eigen/src/LU/Inverse.h +++ b/extern/Eigen3/Eigen/src/LU/Inverse.h @@ -3,28 +3,15 @@ // // Copyright (C) 2008-2010 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_INVERSE_H #define EIGEN_INVERSE_H +namespace Eigen { + namespace internal { /********************************** @@ -286,7 +273,7 @@ struct inverse_impl : public ReturnByValue > typedef typename MatrixType::Index Index; typedef typename internal::eval::type MatrixTypeNested; typedef typename remove_all::type MatrixTypeNestedCleaned; - const MatrixTypeNested m_matrix; + MatrixTypeNested m_matrix; inverse_impl(const MatrixType& matrix) : m_matrix(matrix) @@ -404,4 +391,6 @@ inline void MatrixBase::computeInverseWithCheck( computeInverseAndDetWithCheck(inverse,determinant,invertible,absDeterminantThreshold); } +} // end namespace Eigen + #endif // EIGEN_INVERSE_H diff --git a/extern/Eigen3/Eigen/src/LU/PartialPivLU.h b/extern/Eigen3/Eigen/src/LU/PartialPivLU.h index 09394b01f5b..c9ff9dd5a36 100644 --- a/extern/Eigen3/Eigen/src/LU/PartialPivLU.h +++ b/extern/Eigen3/Eigen/src/LU/PartialPivLU.h @@ -4,28 +4,15 @@ // Copyright (C) 2006-2009 Benoit Jacob // Copyright (C) 2009 Gael Guennebaud // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_PARTIALLU_H #define EIGEN_PARTIALLU_H +namespace Eigen { + /** \ingroup LU_Module * * \class PartialPivLU @@ -506,4 +493,6 @@ MatrixBase::lu() const } #endif +} // end namespace Eigen + #endif // EIGEN_PARTIALLU_H diff --git a/extern/Eigen3/Eigen/src/LU/PartialPivLU_MKL.h b/extern/Eigen3/Eigen/src/LU/PartialPivLU_MKL.h new file mode 100644 index 00000000000..9035953c82f --- /dev/null +++ b/extern/Eigen3/Eigen/src/LU/PartialPivLU_MKL.h @@ -0,0 +1,85 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * LU decomposition with partial pivoting based on LAPACKE_?getrf function. + ******************************************************************************** +*/ + +#ifndef EIGEN_PARTIALLU_LAPACK_H +#define EIGEN_PARTIALLU_LAPACK_H + +#include "Eigen/src/Core/util/MKL_support.h" + +namespace Eigen { + +namespace internal { + +/** \internal Specialization for the data types supported by MKL */ + +#define EIGEN_MKL_LU_PARTPIV(EIGTYPE, MKLTYPE, MKLPREFIX) \ +template \ +struct partial_lu_impl \ +{ \ + /* \internal performs the LU decomposition in-place of the matrix represented */ \ + static lapack_int blocked_lu(lapack_int rows, lapack_int cols, EIGTYPE* lu_data, lapack_int luStride, lapack_int* row_transpositions, lapack_int& nb_transpositions, lapack_int maxBlockSize=256) \ + { \ + EIGEN_UNUSED_VARIABLE(maxBlockSize);\ + lapack_int matrix_order, first_zero_pivot; \ + lapack_int m, n, lda, *ipiv, info; \ + EIGTYPE* a; \ +/* Set up parameters for ?getrf */ \ + matrix_order = StorageOrder==RowMajor ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; \ + lda = luStride; \ + a = lu_data; \ + ipiv = row_transpositions; \ + m = rows; \ + n = cols; \ + nb_transpositions = 0; \ +\ + info = LAPACKE_##MKLPREFIX##getrf( matrix_order, m, n, (MKLTYPE*)a, lda, ipiv ); \ +\ + for(int i=0;i= 0); \ +/* something should be done with nb_transpositions */ \ +\ + first_zero_pivot = info; \ + return first_zero_pivot; \ + } \ +}; + +EIGEN_MKL_LU_PARTPIV(double, double, d) +EIGEN_MKL_LU_PARTPIV(float, float, s) +EIGEN_MKL_LU_PARTPIV(dcomplex, MKL_Complex16, z) +EIGEN_MKL_LU_PARTPIV(scomplex, MKL_Complex8, c) + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_PARTIALLU_LAPACK_H diff --git a/extern/Eigen3/Eigen/src/LU/arch/Inverse_SSE.h b/extern/Eigen3/Eigen/src/LU/arch/Inverse_SSE.h index 4c6153f0aff..60b7a23763e 100644 --- a/extern/Eigen3/Eigen/src/LU/arch/Inverse_SSE.h +++ b/extern/Eigen3/Eigen/src/LU/arch/Inverse_SSE.h @@ -5,24 +5,9 @@ // Copyright (C) 2010 Gael Guennebaud // Copyright (C) 2009 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // The SSE code for the 4x4 float and double matrix inverse in this file // comes from the following Intel's library: @@ -42,6 +27,8 @@ #ifndef EIGEN_INVERSE_SSE_H #define EIGEN_INVERSE_SSE_H +namespace Eigen { + namespace internal { template @@ -335,6 +322,8 @@ struct compute_inverse_size4 } }; -} +} // end namespace internal + +} // end namespace Eigen #endif // EIGEN_INVERSE_SSE_H diff --git a/extern/Eigen3/Eigen/src/OrderingMethods/Amd.h b/extern/Eigen3/Eigen/src/OrderingMethods/Amd.h new file mode 100644 index 00000000000..ce04852b872 --- /dev/null +++ b/extern/Eigen3/Eigen/src/OrderingMethods/Amd.h @@ -0,0 +1,439 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/* + +NOTE: this routine has been adapted from the CSparse library: + +Copyright (c) 2006, Timothy A. Davis. +http://www.cise.ufl.edu/research/sparse/CSparse + +CSparse is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +CSparse is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this Module; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "../Core/util/NonMPL2.h" + +#ifndef EIGEN_SPARSE_AMD_H +#define EIGEN_SPARSE_AMD_H + +namespace Eigen { + +namespace internal { + +template inline T amd_flip(const T& i) { return -i-2; } +template inline T amd_unflip(const T& i) { return i<0 ? amd_flip(i) : i; } +template inline bool amd_marked(const T0* w, const T1& j) { return w[j]<0; } +template inline void amd_mark(const T0* w, const T1& j) { return w[j] = amd_flip(w[j]); } + +/* clear w */ +template +static int cs_wclear (Index mark, Index lemax, Index *w, Index n) +{ + Index k; + if(mark < 2 || (mark + lemax < 0)) + { + for(k = 0; k < n; k++) + if(w[k] != 0) + w[k] = 1; + mark = 2; + } + return (mark); /* at this point, w[0..n-1] < mark holds */ +} + +/* depth-first search and postorder of a tree rooted at node j */ +template +Index cs_tdfs(Index j, Index k, Index *head, const Index *next, Index *post, Index *stack) +{ + int i, p, top = 0; + if(!head || !next || !post || !stack) return (-1); /* check inputs */ + stack[0] = j; /* place j on the stack */ + while (top >= 0) /* while (stack is not empty) */ + { + p = stack[top]; /* p = top of stack */ + i = head[p]; /* i = youngest child of p */ + if(i == -1) + { + top--; /* p has no unordered children left */ + post[k++] = p; /* node p is the kth postordered node */ + } + else + { + head[p] = next[i]; /* remove i from children of p */ + stack[++top] = i; /* start dfs on child node i */ + } + } + return k; +} + + +/** \internal + * Approximate minimum degree ordering algorithm. + * \returns the permutation P reducing the fill-in of the input matrix \a C + * The input matrix \a C must be a selfadjoint compressed column major SparseMatrix object. Both the upper and lower parts have to be stored, but the diagonal entries are optional. + * On exit the values of C are destroyed */ +template +void minimum_degree_ordering(SparseMatrix& C, PermutationMatrix& perm) +{ + using std::sqrt; + typedef SparseMatrix CCS; + + int d, dk, dext, lemax = 0, e, elenk, eln, i, j, k, k1, + k2, k3, jlast, ln, dense, nzmax, mindeg = 0, nvi, nvj, nvk, mark, wnvi, + ok, nel = 0, p, p1, p2, p3, p4, pj, pk, pk1, pk2, pn, q, t; + unsigned int h; + + Index n = C.cols(); + dense = std::max (16, Index(10 * sqrt(double(n)))); /* find dense threshold */ + dense = std::min (n-2, dense); + + Index cnz = C.nonZeros(); + perm.resize(n+1); + t = cnz + cnz/5 + 2*n; /* add elbow room to C */ + C.resizeNonZeros(t); + + Index* W = new Index[8*(n+1)]; /* get workspace */ + Index* len = W; + Index* nv = W + (n+1); + Index* next = W + 2*(n+1); + Index* head = W + 3*(n+1); + Index* elen = W + 4*(n+1); + Index* degree = W + 5*(n+1); + Index* w = W + 6*(n+1); + Index* hhead = W + 7*(n+1); + Index* last = perm.indices().data(); /* use P as workspace for last */ + + /* --- Initialize quotient graph ---------------------------------------- */ + Index* Cp = C.outerIndexPtr(); + Index* Ci = C.innerIndexPtr(); + for(k = 0; k < n; k++) + len[k] = Cp[k+1] - Cp[k]; + len[n] = 0; + nzmax = t; + + for(i = 0; i <= n; i++) + { + head[i] = -1; // degree list i is empty + last[i] = -1; + next[i] = -1; + hhead[i] = -1; // hash list i is empty + nv[i] = 1; // node i is just one node + w[i] = 1; // node i is alive + elen[i] = 0; // Ek of node i is empty + degree[i] = len[i]; // degree of node i + } + mark = internal::cs_wclear(0, 0, w, n); /* clear w */ + elen[n] = -2; /* n is a dead element */ + Cp[n] = -1; /* n is a root of assembly tree */ + w[n] = 0; /* n is a dead element */ + + /* --- Initialize degree lists ------------------------------------------ */ + for(i = 0; i < n; i++) + { + d = degree[i]; + if(d == 0) /* node i is empty */ + { + elen[i] = -2; /* element i is dead */ + nel++; + Cp[i] = -1; /* i is a root of assembly tree */ + w[i] = 0; + } + else if(d > dense) /* node i is dense */ + { + nv[i] = 0; /* absorb i into element n */ + elen[i] = -1; /* node i is dead */ + nel++; + Cp[i] = amd_flip (n); + nv[n]++; + } + else + { + if(head[d] != -1) last[head[d]] = i; + next[i] = head[d]; /* put node i in degree list d */ + head[d] = i; + } + } + + while (nel < n) /* while (selecting pivots) do */ + { + /* --- Select node of minimum approximate degree -------------------- */ + for(k = -1; mindeg < n && (k = head[mindeg]) == -1; mindeg++) {} + if(next[k] != -1) last[next[k]] = -1; + head[mindeg] = next[k]; /* remove k from degree list */ + elenk = elen[k]; /* elenk = |Ek| */ + nvk = nv[k]; /* # of nodes k represents */ + nel += nvk; /* nv[k] nodes of A eliminated */ + + /* --- Garbage collection ------------------------------------------- */ + if(elenk > 0 && cnz + mindeg >= nzmax) + { + for(j = 0; j < n; j++) + { + if((p = Cp[j]) >= 0) /* j is a live node or element */ + { + Cp[j] = Ci[p]; /* save first entry of object */ + Ci[p] = amd_flip (j); /* first entry is now amd_flip(j) */ + } + } + for(q = 0, p = 0; p < cnz; ) /* scan all of memory */ + { + if((j = amd_flip (Ci[p++])) >= 0) /* found object j */ + { + Ci[q] = Cp[j]; /* restore first entry of object */ + Cp[j] = q++; /* new pointer to object j */ + for(k3 = 0; k3 < len[j]-1; k3++) Ci[q++] = Ci[p++]; + } + } + cnz = q; /* Ci[cnz...nzmax-1] now free */ + } + + /* --- Construct new element ---------------------------------------- */ + dk = 0; + nv[k] = -nvk; /* flag k as in Lk */ + p = Cp[k]; + pk1 = (elenk == 0) ? p : cnz; /* do in place if elen[k] == 0 */ + pk2 = pk1; + for(k1 = 1; k1 <= elenk + 1; k1++) + { + if(k1 > elenk) + { + e = k; /* search the nodes in k */ + pj = p; /* list of nodes starts at Ci[pj]*/ + ln = len[k] - elenk; /* length of list of nodes in k */ + } + else + { + e = Ci[p++]; /* search the nodes in e */ + pj = Cp[e]; + ln = len[e]; /* length of list of nodes in e */ + } + for(k2 = 1; k2 <= ln; k2++) + { + i = Ci[pj++]; + if((nvi = nv[i]) <= 0) continue; /* node i dead, or seen */ + dk += nvi; /* degree[Lk] += size of node i */ + nv[i] = -nvi; /* negate nv[i] to denote i in Lk*/ + Ci[pk2++] = i; /* place i in Lk */ + if(next[i] != -1) last[next[i]] = last[i]; + if(last[i] != -1) /* remove i from degree list */ + { + next[last[i]] = next[i]; + } + else + { + head[degree[i]] = next[i]; + } + } + if(e != k) + { + Cp[e] = amd_flip (k); /* absorb e into k */ + w[e] = 0; /* e is now a dead element */ + } + } + if(elenk != 0) cnz = pk2; /* Ci[cnz...nzmax] is free */ + degree[k] = dk; /* external degree of k - |Lk\i| */ + Cp[k] = pk1; /* element k is in Ci[pk1..pk2-1] */ + len[k] = pk2 - pk1; + elen[k] = -2; /* k is now an element */ + + /* --- Find set differences ----------------------------------------- */ + mark = internal::cs_wclear(mark, lemax, w, n); /* clear w if necessary */ + for(pk = pk1; pk < pk2; pk++) /* scan 1: find |Le\Lk| */ + { + i = Ci[pk]; + if((eln = elen[i]) <= 0) continue;/* skip if elen[i] empty */ + nvi = -nv[i]; /* nv[i] was negated */ + wnvi = mark - nvi; + for(p = Cp[i]; p <= Cp[i] + eln - 1; p++) /* scan Ei */ + { + e = Ci[p]; + if(w[e] >= mark) + { + w[e] -= nvi; /* decrement |Le\Lk| */ + } + else if(w[e] != 0) /* ensure e is a live element */ + { + w[e] = degree[e] + wnvi; /* 1st time e seen in scan 1 */ + } + } + } + + /* --- Degree update ------------------------------------------------ */ + for(pk = pk1; pk < pk2; pk++) /* scan2: degree update */ + { + i = Ci[pk]; /* consider node i in Lk */ + p1 = Cp[i]; + p2 = p1 + elen[i] - 1; + pn = p1; + for(h = 0, d = 0, p = p1; p <= p2; p++) /* scan Ei */ + { + e = Ci[p]; + if(w[e] != 0) /* e is an unabsorbed element */ + { + dext = w[e] - mark; /* dext = |Le\Lk| */ + if(dext > 0) + { + d += dext; /* sum up the set differences */ + Ci[pn++] = e; /* keep e in Ei */ + h += e; /* compute the hash of node i */ + } + else + { + Cp[e] = amd_flip (k); /* aggressive absorb. e->k */ + w[e] = 0; /* e is a dead element */ + } + } + } + elen[i] = pn - p1 + 1; /* elen[i] = |Ei| */ + p3 = pn; + p4 = p1 + len[i]; + for(p = p2 + 1; p < p4; p++) /* prune edges in Ai */ + { + j = Ci[p]; + if((nvj = nv[j]) <= 0) continue; /* node j dead or in Lk */ + d += nvj; /* degree(i) += |j| */ + Ci[pn++] = j; /* place j in node list of i */ + h += j; /* compute hash for node i */ + } + if(d == 0) /* check for mass elimination */ + { + Cp[i] = amd_flip (k); /* absorb i into k */ + nvi = -nv[i]; + dk -= nvi; /* |Lk| -= |i| */ + nvk += nvi; /* |k| += nv[i] */ + nel += nvi; + nv[i] = 0; + elen[i] = -1; /* node i is dead */ + } + else + { + degree[i] = std::min (degree[i], d); /* update degree(i) */ + Ci[pn] = Ci[p3]; /* move first node to end */ + Ci[p3] = Ci[p1]; /* move 1st el. to end of Ei */ + Ci[p1] = k; /* add k as 1st element in of Ei */ + len[i] = pn - p1 + 1; /* new len of adj. list of node i */ + h %= n; /* finalize hash of i */ + next[i] = hhead[h]; /* place i in hash bucket */ + hhead[h] = i; + last[i] = h; /* save hash of i in last[i] */ + } + } /* scan2 is done */ + degree[k] = dk; /* finalize |Lk| */ + lemax = std::max(lemax, dk); + mark = internal::cs_wclear(mark+lemax, lemax, w, n); /* clear w */ + + /* --- Supernode detection ------------------------------------------ */ + for(pk = pk1; pk < pk2; pk++) + { + i = Ci[pk]; + if(nv[i] >= 0) continue; /* skip if i is dead */ + h = last[i]; /* scan hash bucket of node i */ + i = hhead[h]; + hhead[h] = -1; /* hash bucket will be empty */ + for(; i != -1 && next[i] != -1; i = next[i], mark++) + { + ln = len[i]; + eln = elen[i]; + for(p = Cp[i]+1; p <= Cp[i] + ln-1; p++) w[Ci[p]] = mark; + jlast = i; + for(j = next[i]; j != -1; ) /* compare i with all j */ + { + ok = (len[j] == ln) && (elen[j] == eln); + for(p = Cp[j] + 1; ok && p <= Cp[j] + ln - 1; p++) + { + if(w[Ci[p]] != mark) ok = 0; /* compare i and j*/ + } + if(ok) /* i and j are identical */ + { + Cp[j] = amd_flip (i); /* absorb j into i */ + nv[i] += nv[j]; + nv[j] = 0; + elen[j] = -1; /* node j is dead */ + j = next[j]; /* delete j from hash bucket */ + next[jlast] = j; + } + else + { + jlast = j; /* j and i are different */ + j = next[j]; + } + } + } + } + + /* --- Finalize new element------------------------------------------ */ + for(p = pk1, pk = pk1; pk < pk2; pk++) /* finalize Lk */ + { + i = Ci[pk]; + if((nvi = -nv[i]) <= 0) continue;/* skip if i is dead */ + nv[i] = nvi; /* restore nv[i] */ + d = degree[i] + dk - nvi; /* compute external degree(i) */ + d = std::min (d, n - nel - nvi); + if(head[d] != -1) last[head[d]] = i; + next[i] = head[d]; /* put i back in degree list */ + last[i] = -1; + head[d] = i; + mindeg = std::min (mindeg, d); /* find new minimum degree */ + degree[i] = d; + Ci[p++] = i; /* place i in Lk */ + } + nv[k] = nvk; /* # nodes absorbed into k */ + if((len[k] = p-pk1) == 0) /* length of adj list of element k*/ + { + Cp[k] = -1; /* k is a root of the tree */ + w[k] = 0; /* k is now a dead element */ + } + if(elenk != 0) cnz = p; /* free unused space in Lk */ + } + + /* --- Postordering ----------------------------------------------------- */ + for(i = 0; i < n; i++) Cp[i] = amd_flip (Cp[i]);/* fix assembly tree */ + for(j = 0; j <= n; j++) head[j] = -1; + for(j = n; j >= 0; j--) /* place unordered nodes in lists */ + { + if(nv[j] > 0) continue; /* skip if j is an element */ + next[j] = head[Cp[j]]; /* place j in list of its parent */ + head[Cp[j]] = j; + } + for(e = n; e >= 0; e--) /* place elements in lists */ + { + if(nv[e] <= 0) continue; /* skip unless e is an element */ + if(Cp[e] != -1) + { + next[e] = head[Cp[e]]; /* place e in list of its parent */ + head[Cp[e]] = e; + } + } + for(k = 0, i = 0; i <= n; i++) /* postorder the assembly tree */ + { + if(Cp[i] == -1) k = internal::cs_tdfs(i, k, head, next, perm.indices().data(), w); + } + + perm.indices().conservativeResize(n); + + delete[] W; +} + +} // namespace internal + +} // end namespace Eigen + +#endif // EIGEN_SPARSE_AMD_H diff --git a/extern/Eigen3/Eigen/src/PaStiXSupport/PaStiXSupport.h b/extern/Eigen3/Eigen/src/PaStiXSupport/PaStiXSupport.h new file mode 100644 index 00000000000..82e137c645a --- /dev/null +++ b/extern/Eigen3/Eigen/src/PaStiXSupport/PaStiXSupport.h @@ -0,0 +1,742 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2012 Désiré Nuentsa-Wakam +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_PASTIXSUPPORT_H +#define EIGEN_PASTIXSUPPORT_H + +namespace Eigen { + +/** \ingroup PaStiXSupport_Module + * \brief Interface to the PaStix solver + * + * This class is used to solve the linear systems A.X = B via the PaStix library. + * The matrix can be either real or complex, symmetric or not. + * + * \sa TutorialSparseDirectSolvers + */ +template class PastixLU; +template class PastixLLT; +template class PastixLDLT; + +namespace internal +{ + + template struct pastix_traits; + + template + struct pastix_traits< PastixLU<_MatrixType> > + { + typedef _MatrixType MatrixType; + typedef typename _MatrixType::Scalar Scalar; + typedef typename _MatrixType::RealScalar RealScalar; + typedef typename _MatrixType::Index Index; + }; + + template + struct pastix_traits< PastixLLT<_MatrixType,Options> > + { + typedef _MatrixType MatrixType; + typedef typename _MatrixType::Scalar Scalar; + typedef typename _MatrixType::RealScalar RealScalar; + typedef typename _MatrixType::Index Index; + }; + + template + struct pastix_traits< PastixLDLT<_MatrixType,Options> > + { + typedef _MatrixType MatrixType; + typedef typename _MatrixType::Scalar Scalar; + typedef typename _MatrixType::RealScalar RealScalar; + typedef typename _MatrixType::Index Index; + }; + + void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, float *vals, int *perm, int * invp, float *x, int nbrhs, int *iparm, double *dparm) + { + if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; } + if (nbrhs == 0) {x = NULL; nbrhs=1;} + s_pastix(pastix_data, pastix_comm, n, ptr, idx, vals, perm, invp, x, nbrhs, iparm, dparm); + } + + void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, double *vals, int *perm, int * invp, double *x, int nbrhs, int *iparm, double *dparm) + { + if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; } + if (nbrhs == 0) {x = NULL; nbrhs=1;} + d_pastix(pastix_data, pastix_comm, n, ptr, idx, vals, perm, invp, x, nbrhs, iparm, dparm); + } + + void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, std::complex *vals, int *perm, int * invp, std::complex *x, int nbrhs, int *iparm, double *dparm) + { + if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; } + if (nbrhs == 0) {x = NULL; nbrhs=1;} + c_pastix(pastix_data, pastix_comm, n, ptr, idx, reinterpret_cast(vals), perm, invp, reinterpret_cast(x), nbrhs, iparm, dparm); + } + + void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, std::complex *vals, int *perm, int * invp, std::complex *x, int nbrhs, int *iparm, double *dparm) + { + if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; } + if (nbrhs == 0) {x = NULL; nbrhs=1;} + z_pastix(pastix_data, pastix_comm, n, ptr, idx, reinterpret_cast(vals), perm, invp, reinterpret_cast(x), nbrhs, iparm, dparm); + } + + // Convert the matrix to Fortran-style Numbering + template + void c_to_fortran_numbering (MatrixType& mat) + { + if ( !(mat.outerIndexPtr()[0]) ) + { + int i; + for(i = 0; i <= mat.rows(); ++i) + ++mat.outerIndexPtr()[i]; + for(i = 0; i < mat.nonZeros(); ++i) + ++mat.innerIndexPtr()[i]; + } + } + + // Convert to C-style Numbering + template + void fortran_to_c_numbering (MatrixType& mat) + { + // Check the Numbering + if ( mat.outerIndexPtr()[0] == 1 ) + { // Convert to C-style numbering + int i; + for(i = 0; i <= mat.rows(); ++i) + --mat.outerIndexPtr()[i]; + for(i = 0; i < mat.nonZeros(); ++i) + --mat.innerIndexPtr()[i]; + } + } +} + +// This is the base class to interface with PaStiX functions. +// Users should not used this class directly. +template +class PastixBase : internal::noncopyable +{ + public: + typedef typename internal::pastix_traits::MatrixType _MatrixType; + typedef _MatrixType MatrixType; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + typedef Matrix Vector; + typedef SparseMatrix ColSpMatrix; + + public: + + PastixBase() : m_initisOk(false), m_analysisIsOk(false), m_factorizationIsOk(false), m_isInitialized(false), m_pastixdata(0), m_size(0) + { + init(); + } + + ~PastixBase() + { + clean(); + } + + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ + template + inline const internal::solve_retval + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "Pastix solver is not initialized."); + eigen_assert(rows()==b.rows() + && "PastixBase::solve(): invalid number of rows of the right hand side matrix b"); + return internal::solve_retval(*this, b.derived()); + } + + template + bool _solve (const MatrixBase &b, MatrixBase &x) const; + + /** \internal */ + template + void _solve_sparse(const Rhs& b, SparseMatrix &dest) const + { + eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); + eigen_assert(rows()==b.rows()); + + // we process the sparse rhs per block of NbColsAtOnce columns temporarily stored into a dense matrix. + static const int NbColsAtOnce = 1; + int rhsCols = b.cols(); + int size = b.rows(); + Eigen::Matrix tmp(size,rhsCols); + for(int k=0; k(rhsCols-k, NbColsAtOnce); + tmp.leftCols(actualCols) = b.middleCols(k,actualCols); + tmp.leftCols(actualCols) = derived().solve(tmp.leftCols(actualCols)); + dest.middleCols(k,actualCols) = tmp.leftCols(actualCols).sparseView(); + } + } + + Derived& derived() + { + return *static_cast(this); + } + const Derived& derived() const + { + return *static_cast(this); + } + + /** Returns a reference to the integer vector IPARM of PaStiX parameters + * to modify the default parameters. + * The statistics related to the different phases of factorization and solve are saved here as well + * \sa analyzePattern() factorize() + */ + Array& iparm() + { + return m_iparm; + } + + /** Return a reference to a particular index parameter of the IPARM vector + * \sa iparm() + */ + + int& iparm(int idxparam) + { + return m_iparm(idxparam); + } + + /** Returns a reference to the double vector DPARM of PaStiX parameters + * The statistics related to the different phases of factorization and solve are saved here as well + * \sa analyzePattern() factorize() + */ + Array& dparm() + { + return m_dparm; + } + + + /** Return a reference to a particular index parameter of the DPARM vector + * \sa dparm() + */ + double& dparm(int idxparam) + { + return m_dparm(idxparam); + } + + inline Index cols() const { return m_size; } + inline Index rows() const { return m_size; } + + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was succesful, + * \c NumericalIssue if the PaStiX reports a problem + * \c InvalidInput if the input matrix is invalid + * + * \sa iparm() + */ + ComputationInfo info() const + { + eigen_assert(m_isInitialized && "Decomposition is not initialized."); + return m_info; + } + + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ + template + inline const internal::sparse_solve_retval + solve(const SparseMatrixBase& b) const + { + eigen_assert(m_isInitialized && "Pastix LU, LLT or LDLT is not initialized."); + eigen_assert(rows()==b.rows() + && "PastixBase::solve(): invalid number of rows of the right hand side matrix b"); + return internal::sparse_solve_retval(*this, b.derived()); + } + + protected: + + // Initialize the Pastix data structure, check the matrix + void init(); + + // Compute the ordering and the symbolic factorization + void analyzePattern(ColSpMatrix& mat); + + // Compute the numerical factorization + void factorize(ColSpMatrix& mat); + + // Free all the data allocated by Pastix + void clean() + { + eigen_assert(m_initisOk && "The Pastix structure should be allocated first"); + m_iparm(IPARM_START_TASK) = API_TASK_CLEAN; + m_iparm(IPARM_END_TASK) = API_TASK_CLEAN; + internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, 0, 0, 0, (Scalar*)0, + m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data()); + } + + void compute(ColSpMatrix& mat); + + int m_initisOk; + int m_analysisIsOk; + int m_factorizationIsOk; + bool m_isInitialized; + mutable ComputationInfo m_info; + mutable pastix_data_t *m_pastixdata; // Data structure for pastix + mutable int m_comm; // The MPI communicator identifier + mutable Matrix m_iparm; // integer vector for the input parameters + mutable Matrix m_dparm; // Scalar vector for the input parameters + mutable Matrix m_perm; // Permutation vector + mutable Matrix m_invp; // Inverse permutation vector + mutable int m_size; // Size of the matrix +}; + + /** Initialize the PaStiX data structure. + *A first call to this function fills iparm and dparm with the default PaStiX parameters + * \sa iparm() dparm() + */ +template +void PastixBase::init() +{ + m_size = 0; + m_iparm.setZero(IPARM_SIZE); + m_dparm.setZero(DPARM_SIZE); + + m_iparm(IPARM_MODIFY_PARAMETER) = API_NO; + pastix(&m_pastixdata, MPI_COMM_WORLD, + 0, 0, 0, 0, + 0, 0, 0, 1, m_iparm.data(), m_dparm.data()); + + m_iparm[IPARM_MATRIX_VERIFICATION] = API_NO; + m_iparm[IPARM_VERBOSE] = 2; + m_iparm[IPARM_ORDERING] = API_ORDER_SCOTCH; + m_iparm[IPARM_INCOMPLETE] = API_NO; + m_iparm[IPARM_OOC_LIMIT] = 2000; + m_iparm[IPARM_RHS_MAKING] = API_RHS_B; + m_iparm(IPARM_MATRIX_VERIFICATION) = API_NO; + + m_iparm(IPARM_START_TASK) = API_TASK_INIT; + m_iparm(IPARM_END_TASK) = API_TASK_INIT; + internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, 0, 0, 0, (Scalar*)0, + 0, 0, 0, 0, m_iparm.data(), m_dparm.data()); + + // Check the returned error + if(m_iparm(IPARM_ERROR_NUMBER)) { + m_info = InvalidInput; + m_initisOk = false; + } + else { + m_info = Success; + m_initisOk = true; + } +} + +template +void PastixBase::compute(ColSpMatrix& mat) +{ + eigen_assert(mat.rows() == mat.cols() && "The input matrix should be squared"); + + analyzePattern(mat); + factorize(mat); + + m_iparm(IPARM_MATRIX_VERIFICATION) = API_NO; + m_isInitialized = m_factorizationIsOk; +} + + +template +void PastixBase::analyzePattern(ColSpMatrix& mat) +{ + eigen_assert(m_initisOk && "The initialization of PaSTiX failed"); + + // clean previous calls + if(m_size>0) + clean(); + + m_size = mat.rows(); + m_perm.resize(m_size); + m_invp.resize(m_size); + + m_iparm(IPARM_START_TASK) = API_TASK_ORDERING; + m_iparm(IPARM_END_TASK) = API_TASK_ANALYSE; + internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, m_size, mat.outerIndexPtr(), mat.innerIndexPtr(), + mat.valuePtr(), m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data()); + + // Check the returned error + if(m_iparm(IPARM_ERROR_NUMBER)) + { + m_info = NumericalIssue; + m_analysisIsOk = false; + } + else + { + m_info = Success; + m_analysisIsOk = true; + } +} + +template +void PastixBase::factorize(ColSpMatrix& mat) +{ +// if(&m_cpyMat != &mat) m_cpyMat = mat; + eigen_assert(m_analysisIsOk && "The analysis phase should be called before the factorization phase"); + m_iparm(IPARM_START_TASK) = API_TASK_NUMFACT; + m_iparm(IPARM_END_TASK) = API_TASK_NUMFACT; + m_size = mat.rows(); + + internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, m_size, mat.outerIndexPtr(), mat.innerIndexPtr(), + mat.valuePtr(), m_perm.data(), m_invp.data(), 0, 0, m_iparm.data(), m_dparm.data()); + + // Check the returned error + if(m_iparm(IPARM_ERROR_NUMBER)) + { + m_info = NumericalIssue; + m_factorizationIsOk = false; + m_isInitialized = false; + } + else + { + m_info = Success; + m_factorizationIsOk = true; + m_isInitialized = true; + } +} + +/* Solve the system */ +template +template +bool PastixBase::_solve (const MatrixBase &b, MatrixBase &x) const +{ + eigen_assert(m_isInitialized && "The matrix should be factorized first"); + EIGEN_STATIC_ASSERT((Dest::Flags&RowMajorBit)==0, + THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); + int rhs = 1; + + x = b; /* on return, x is overwritten by the computed solution */ + + for (int i = 0; i < b.cols(); i++){ + m_iparm[IPARM_START_TASK] = API_TASK_SOLVE; + m_iparm[IPARM_END_TASK] = API_TASK_REFINE; + + internal::eigen_pastix(&m_pastixdata, MPI_COMM_WORLD, x.rows(), 0, 0, 0, + m_perm.data(), m_invp.data(), &x(0, i), rhs, m_iparm.data(), m_dparm.data()); + } + + // Check the returned error + m_info = m_iparm(IPARM_ERROR_NUMBER)==0 ? Success : NumericalIssue; + + return m_iparm(IPARM_ERROR_NUMBER)==0; +} + +/** \ingroup PaStiXSupport_Module + * \class PastixLU + * \brief Sparse direct LU solver based on PaStiX library + * + * This class is used to solve the linear systems A.X = B with a supernodal LU + * factorization in the PaStiX library. The matrix A should be squared and nonsingular + * PaStiX requires that the matrix A has a symmetric structural pattern. + * This interface can symmetrize the input matrix otherwise. + * The vectors or matrices X and B can be either dense or sparse. + * + * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * \tparam IsStrSym Indicates if the input matrix has a symmetric pattern, default is false + * NOTE : Note that if the analysis and factorization phase are called separately, + * the input matrix will be symmetrized at each call, hence it is advised to + * symmetrize the matrix in a end-user program and set \p IsStrSym to true + * + * \sa \ref TutorialSparseDirectSolvers + * + */ +template +class PastixLU : public PastixBase< PastixLU<_MatrixType> > +{ + public: + typedef _MatrixType MatrixType; + typedef PastixBase > Base; + typedef typename Base::ColSpMatrix ColSpMatrix; + typedef typename MatrixType::Index Index; + + public: + PastixLU() : Base() + { + init(); + } + + PastixLU(const MatrixType& matrix):Base() + { + init(); + compute(matrix); + } + /** Compute the LU supernodal factorization of \p matrix. + * iparm and dparm can be used to tune the PaStiX parameters. + * see the PaStiX user's manual + * \sa analyzePattern() factorize() + */ + void compute (const MatrixType& matrix) + { + m_structureIsUptodate = false; + ColSpMatrix temp; + grabMatrix(matrix, temp); + Base::compute(temp); + } + /** Compute the LU symbolic factorization of \p matrix using its sparsity pattern. + * Several ordering methods can be used at this step. See the PaStiX user's manual. + * The result of this operation can be used with successive matrices having the same pattern as \p matrix + * \sa factorize() + */ + void analyzePattern(const MatrixType& matrix) + { + m_structureIsUptodate = false; + ColSpMatrix temp; + grabMatrix(matrix, temp); + Base::analyzePattern(temp); + } + + /** Compute the LU supernodal factorization of \p matrix + * WARNING The matrix \p matrix should have the same structural pattern + * as the same used in the analysis phase. + * \sa analyzePattern() + */ + void factorize(const MatrixType& matrix) + { + ColSpMatrix temp; + grabMatrix(matrix, temp); + Base::factorize(temp); + } + protected: + + void init() + { + m_structureIsUptodate = false; + m_iparm(IPARM_SYM) = API_SYM_NO; + m_iparm(IPARM_FACTORIZATION) = API_FACT_LU; + } + + void grabMatrix(const MatrixType& matrix, ColSpMatrix& out) + { + if(IsStrSym) + out = matrix; + else + { + if(!m_structureIsUptodate) + { + // update the transposed structure + m_transposedStructure = matrix.transpose(); + + // Set the elements of the matrix to zero + for (Index j=0; j + * \tparam UpLo The part of the matrix to use : Lower or Upper. The default is Lower as required by PaStiX + * + * \sa \ref TutorialSparseDirectSolvers + */ +template +class PastixLLT : public PastixBase< PastixLLT<_MatrixType, _UpLo> > +{ + public: + typedef _MatrixType MatrixType; + typedef PastixBase > Base; + typedef typename Base::ColSpMatrix ColSpMatrix; + + public: + enum { UpLo = _UpLo }; + PastixLLT() : Base() + { + init(); + } + + PastixLLT(const MatrixType& matrix):Base() + { + init(); + compute(matrix); + } + + /** Compute the L factor of the LL^T supernodal factorization of \p matrix + * \sa analyzePattern() factorize() + */ + void compute (const MatrixType& matrix) + { + ColSpMatrix temp; + grabMatrix(matrix, temp); + Base::compute(temp); + } + + /** Compute the LL^T symbolic factorization of \p matrix using its sparsity pattern + * The result of this operation can be used with successive matrices having the same pattern as \p matrix + * \sa factorize() + */ + void analyzePattern(const MatrixType& matrix) + { + ColSpMatrix temp; + grabMatrix(matrix, temp); + Base::analyzePattern(temp); + } + /** Compute the LL^T supernodal numerical factorization of \p matrix + * \sa analyzePattern() + */ + void factorize(const MatrixType& matrix) + { + ColSpMatrix temp; + grabMatrix(matrix, temp); + Base::factorize(temp); + } + protected: + using Base::m_iparm; + + void init() + { + m_iparm(IPARM_SYM) = API_SYM_YES; + m_iparm(IPARM_FACTORIZATION) = API_FACT_LLT; + } + + void grabMatrix(const MatrixType& matrix, ColSpMatrix& out) + { + // Pastix supports only lower, column-major matrices + out.template selfadjointView() = matrix.template selfadjointView(); + internal::c_to_fortran_numbering(out); + } +}; + +/** \ingroup PaStiXSupport_Module + * \class PastixLDLT + * \brief A sparse direct supernodal Cholesky (LLT) factorization and solver based on the PaStiX library + * + * This class is used to solve the linear systems A.X = B via a LDL^T supernodal Cholesky factorization + * available in the PaStiX library. The matrix A should be symmetric and positive definite + * WARNING Selfadjoint complex matrices are not supported in the current version of PaStiX + * The vectors or matrices X and B can be either dense or sparse + * + * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * \tparam UpLo The part of the matrix to use : Lower or Upper. The default is Lower as required by PaStiX + * + * \sa \ref TutorialSparseDirectSolvers + */ +template +class PastixLDLT : public PastixBase< PastixLDLT<_MatrixType, _UpLo> > +{ + public: + typedef _MatrixType MatrixType; + typedef PastixBase > Base; + typedef typename Base::ColSpMatrix ColSpMatrix; + + public: + enum { UpLo = _UpLo }; + PastixLDLT():Base() + { + init(); + } + + PastixLDLT(const MatrixType& matrix):Base() + { + init(); + compute(matrix); + } + + /** Compute the L and D factors of the LDL^T factorization of \p matrix + * \sa analyzePattern() factorize() + */ + void compute (const MatrixType& matrix) + { + ColSpMatrix temp; + grabMatrix(matrix, temp); + Base::compute(temp); + } + + /** Compute the LDL^T symbolic factorization of \p matrix using its sparsity pattern + * The result of this operation can be used with successive matrices having the same pattern as \p matrix + * \sa factorize() + */ + void analyzePattern(const MatrixType& matrix) + { + ColSpMatrix temp; + grabMatrix(matrix, temp); + Base::analyzePattern(temp); + } + /** Compute the LDL^T supernodal numerical factorization of \p matrix + * + */ + void factorize(const MatrixType& matrix) + { + ColSpMatrix temp; + grabMatrix(matrix, temp); + Base::factorize(temp); + } + + protected: + using Base::m_iparm; + + void init() + { + m_iparm(IPARM_SYM) = API_SYM_YES; + m_iparm(IPARM_FACTORIZATION) = API_FACT_LDLT; + } + + void grabMatrix(const MatrixType& matrix, ColSpMatrix& out) + { + // Pastix supports only lower, column-major matrices + out.template selfadjointView() = matrix.template selfadjointView(); + internal::c_to_fortran_numbering(out); + } +}; + +namespace internal { + +template +struct solve_retval, Rhs> + : solve_retval_base, Rhs> +{ + typedef PastixBase<_MatrixType> Dec; + EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec()._solve(rhs(),dst); + } +}; + +template +struct sparse_solve_retval, Rhs> + : sparse_solve_retval_base, Rhs> +{ + typedef PastixBase<_MatrixType> Dec; + EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec()._solve_sparse(rhs(),dst); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif diff --git a/extern/Eigen3/Eigen/src/PardisoSupport/PardisoSupport.h b/extern/Eigen3/Eigen/src/PardisoSupport/PardisoSupport.h new file mode 100644 index 00000000000..e6defc8c39e --- /dev/null +++ b/extern/Eigen3/Eigen/src/PardisoSupport/PardisoSupport.h @@ -0,0 +1,614 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL PARDISO + ******************************************************************************** +*/ + +#ifndef EIGEN_PARDISOSUPPORT_H +#define EIGEN_PARDISOSUPPORT_H + +namespace Eigen { + +template class PardisoLU; +template class PardisoLLT; +template class PardisoLDLT; + +namespace internal +{ + template + struct pardiso_run_selector + { + static Index run( _MKL_DSS_HANDLE_t pt, Index maxfct, Index mnum, Index type, Index phase, Index n, void *a, + Index *ia, Index *ja, Index *perm, Index nrhs, Index *iparm, Index msglvl, void *b, void *x) + { + Index error = 0; + ::pardiso(pt, &maxfct, &mnum, &type, &phase, &n, a, ia, ja, perm, &nrhs, iparm, &msglvl, b, x, &error); + return error; + } + }; + template<> + struct pardiso_run_selector + { + typedef long long int Index; + static Index run( _MKL_DSS_HANDLE_t pt, Index maxfct, Index mnum, Index type, Index phase, Index n, void *a, + Index *ia, Index *ja, Index *perm, Index nrhs, Index *iparm, Index msglvl, void *b, void *x) + { + Index error = 0; + ::pardiso_64(pt, &maxfct, &mnum, &type, &phase, &n, a, ia, ja, perm, &nrhs, iparm, &msglvl, b, x, &error); + return error; + } + }; + + template struct pardiso_traits; + + template + struct pardiso_traits< PardisoLU<_MatrixType> > + { + typedef _MatrixType MatrixType; + typedef typename _MatrixType::Scalar Scalar; + typedef typename _MatrixType::RealScalar RealScalar; + typedef typename _MatrixType::Index Index; + }; + + template + struct pardiso_traits< PardisoLLT<_MatrixType, Options> > + { + typedef _MatrixType MatrixType; + typedef typename _MatrixType::Scalar Scalar; + typedef typename _MatrixType::RealScalar RealScalar; + typedef typename _MatrixType::Index Index; + }; + + template + struct pardiso_traits< PardisoLDLT<_MatrixType, Options> > + { + typedef _MatrixType MatrixType; + typedef typename _MatrixType::Scalar Scalar; + typedef typename _MatrixType::RealScalar RealScalar; + typedef typename _MatrixType::Index Index; + }; + +} + +template +class PardisoImpl +{ + typedef internal::pardiso_traits Traits; + public: + typedef typename Traits::MatrixType MatrixType; + typedef typename Traits::Scalar Scalar; + typedef typename Traits::RealScalar RealScalar; + typedef typename Traits::Index Index; + typedef SparseMatrix SparseMatrixType; + typedef Matrix VectorType; + typedef Matrix IntRowVectorType; + typedef Matrix IntColVectorType; + enum { + ScalarIsComplex = NumTraits::IsComplex + }; + + PardisoImpl() + { + eigen_assert((sizeof(Index) >= sizeof(_INTEGER_t) && sizeof(Index) <= 8) && "Non-supported index type"); + m_iparm.setZero(); + m_msglvl = 0; // No output + m_initialized = false; + } + + ~PardisoImpl() + { + pardisoRelease(); + } + + inline Index cols() const { return m_size; } + inline Index rows() const { return m_size; } + + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was succesful, + * \c NumericalIssue if the matrix appears to be negative. + */ + ComputationInfo info() const + { + eigen_assert(m_initialized && "Decomposition is not initialized."); + return m_info; + } + + /** \warning for advanced usage only. + * \returns a reference to the parameter array controlling PARDISO. + * See the PARDISO manual to know how to use it. */ + Array& pardisoParameterArray() + { + return m_iparm; + } + + /** Performs a symbolic decomposition on the sparcity of \a matrix. + * + * This function is particularly useful when solving for several problems having the same structure. + * + * \sa factorize() + */ + Derived& analyzePattern(const MatrixType& matrix); + + /** Performs a numeric decomposition of \a matrix + * + * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. + * + * \sa analyzePattern() + */ + Derived& factorize(const MatrixType& matrix); + + Derived& compute(const MatrixType& matrix); + + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ + template + inline const internal::solve_retval + solve(const MatrixBase& b) const + { + eigen_assert(m_initialized && "Pardiso solver is not initialized."); + eigen_assert(rows()==b.rows() + && "PardisoImpl::solve(): invalid number of rows of the right hand side matrix b"); + return internal::solve_retval(*this, b.derived()); + } + + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ + template + inline const internal::sparse_solve_retval + solve(const SparseMatrixBase& b) const + { + eigen_assert(m_initialized && "Pardiso solver is not initialized."); + eigen_assert(rows()==b.rows() + && "PardisoImpl::solve(): invalid number of rows of the right hand side matrix b"); + return internal::sparse_solve_retval(*this, b.derived()); + } + + Derived& derived() + { + return *static_cast(this); + } + const Derived& derived() const + { + return *static_cast(this); + } + + template + bool _solve(const MatrixBase &b, MatrixBase& x) const; + + /** \internal */ + template + void _solve_sparse(const Rhs& b, SparseMatrix &dest) const + { + eigen_assert(m_size==b.rows()); + + // we process the sparse rhs per block of NbColsAtOnce columns temporarily stored into a dense matrix. + static const int NbColsAtOnce = 4; + int rhsCols = b.cols(); + int size = b.rows(); + // Pardiso cannot solve in-place, + // so we need two temporaries + Eigen::Matrix tmp_rhs(size,rhsCols); + Eigen::Matrix tmp_res(size,rhsCols); + for(int k=0; k(rhsCols-k, NbColsAtOnce); + tmp_rhs.leftCols(actualCols) = b.middleCols(k,actualCols); + tmp_res.leftCols(actualCols) = derived().solve(tmp_rhs.leftCols(actualCols)); + dest.middleCols(k,actualCols) = tmp_res.leftCols(actualCols).sparseView(); + } + } + + protected: + void pardisoRelease() + { + if(m_initialized) // Factorization ran at least once + { + internal::pardiso_run_selector::run(m_pt, 1, 1, m_type, -1, m_size, 0, 0, 0, m_perm.data(), 0, + m_iparm.data(), m_msglvl, 0, 0); + } + } + + void pardisoInit(int type) + { + m_type = type; + bool symmetric = abs(m_type) < 10; + m_iparm[0] = 1; // No solver default + m_iparm[1] = 3; // use Metis for the ordering + m_iparm[2] = 1; // Numbers of processors, value of OMP_NUM_THREADS + m_iparm[3] = 0; // No iterative-direct algorithm + m_iparm[4] = 0; // No user fill-in reducing permutation + m_iparm[5] = 0; // Write solution into x + m_iparm[6] = 0; // Not in use + m_iparm[7] = 2; // Max numbers of iterative refinement steps + m_iparm[8] = 0; // Not in use + m_iparm[9] = 13; // Perturb the pivot elements with 1E-13 + m_iparm[10] = symmetric ? 0 : 1; // Use nonsymmetric permutation and scaling MPS + m_iparm[11] = 0; // Not in use + m_iparm[12] = symmetric ? 0 : 1; // Maximum weighted matching algorithm is switched-off (default for symmetric). + // Try m_iparm[12] = 1 in case of inappropriate accuracy + m_iparm[13] = 0; // Output: Number of perturbed pivots + m_iparm[14] = 0; // Not in use + m_iparm[15] = 0; // Not in use + m_iparm[16] = 0; // Not in use + m_iparm[17] = -1; // Output: Number of nonzeros in the factor LU + m_iparm[18] = -1; // Output: Mflops for LU factorization + m_iparm[19] = 0; // Output: Numbers of CG Iterations + + m_iparm[20] = 0; // 1x1 pivoting + m_iparm[26] = 0; // No matrix checker + m_iparm[27] = (sizeof(RealScalar) == 4) ? 1 : 0; + m_iparm[34] = 1; // C indexing + m_iparm[59] = 1; // Automatic switch between In-Core and Out-of-Core modes + } + + protected: + // cached data to reduce reallocation, etc. + + void manageErrorCode(Index error) + { + switch(error) + { + case 0: + m_info = Success; + break; + case -4: + case -7: + m_info = NumericalIssue; + break; + default: + m_info = InvalidInput; + } + } + + mutable SparseMatrixType m_matrix; + ComputationInfo m_info; + bool m_initialized, m_analysisIsOk, m_factorizationIsOk; + Index m_type, m_msglvl; + mutable void *m_pt[64]; + mutable Array m_iparm; + mutable IntColVectorType m_perm; + Index m_size; + + private: + PardisoImpl(PardisoImpl &) {} +}; + +template +Derived& PardisoImpl::compute(const MatrixType& a) +{ + m_size = a.rows(); + eigen_assert(a.rows() == a.cols()); + + pardisoRelease(); + memset(m_pt, 0, sizeof(m_pt)); + m_perm.setZero(m_size); + derived().getMatrix(a); + + Index error; + error = internal::pardiso_run_selector::run(m_pt, 1, 1, m_type, 12, m_size, + m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(), + m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL); + + manageErrorCode(error); + m_analysisIsOk = true; + m_factorizationIsOk = true; + m_initialized = true; + return derived(); +} + +template +Derived& PardisoImpl::analyzePattern(const MatrixType& a) +{ + m_size = a.rows(); + eigen_assert(m_size == a.cols()); + + pardisoRelease(); + memset(m_pt, 0, sizeof(m_pt)); + m_perm.setZero(m_size); + derived().getMatrix(a); + + Index error; + error = internal::pardiso_run_selector::run(m_pt, 1, 1, m_type, 11, m_size, + m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(), + m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL); + + manageErrorCode(error); + m_analysisIsOk = true; + m_factorizationIsOk = false; + m_initialized = true; + return derived(); +} + +template +Derived& PardisoImpl::factorize(const MatrixType& a) +{ + eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); + eigen_assert(m_size == a.rows() && m_size == a.cols()); + + derived().getMatrix(a); + + Index error; + error = internal::pardiso_run_selector::run(m_pt, 1, 1, m_type, 22, m_size, + m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(), + m_perm.data(), 0, m_iparm.data(), m_msglvl, NULL, NULL); + + manageErrorCode(error); + m_factorizationIsOk = true; + return derived(); +} + +template +template +bool PardisoImpl::_solve(const MatrixBase &b, MatrixBase& x) const +{ + if(m_iparm[0] == 0) // Factorization was not computed + return false; + + //Index n = m_matrix.rows(); + Index nrhs = Index(b.cols()); + eigen_assert(m_size==b.rows()); + eigen_assert(((MatrixBase::Flags & RowMajorBit) == 0 || nrhs == 1) && "Row-major right hand sides are not supported"); + eigen_assert(((MatrixBase::Flags & RowMajorBit) == 0 || nrhs == 1) && "Row-major matrices of unknowns are not supported"); + eigen_assert(((nrhs == 1) || b.outerStride() == b.rows())); + + +// switch (transposed) { +// case SvNoTrans : m_iparm[11] = 0 ; break; +// case SvTranspose : m_iparm[11] = 2 ; break; +// case SvAdjoint : m_iparm[11] = 1 ; break; +// default: +// //std::cerr << "Eigen: transposition option \"" << transposed << "\" not supported by the PARDISO backend\n"; +// m_iparm[11] = 0; +// } + + Scalar* rhs_ptr = const_cast(b.derived().data()); + Matrix tmp; + + // Pardiso cannot solve in-place + if(rhs_ptr == x.derived().data()) + { + tmp = b; + rhs_ptr = tmp.data(); + } + + Index error; + error = internal::pardiso_run_selector::run(m_pt, 1, 1, m_type, 33, m_size, + m_matrix.valuePtr(), m_matrix.outerIndexPtr(), m_matrix.innerIndexPtr(), + m_perm.data(), nrhs, m_iparm.data(), m_msglvl, + rhs_ptr, x.derived().data()); + + return error==0; +} + + +/** \ingroup PardisoSupport_Module + * \class PardisoLU + * \brief A sparse direct LU factorization and solver based on the PARDISO library + * + * This class allows to solve for A.X = B sparse linear problems via a direct LU factorization + * using the Intel MKL PARDISO library. The sparse matrix A must be squared and invertible. + * The vectors or matrices X and B can be either dense or sparse. + * + * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * + * \sa \ref TutorialSparseDirectSolvers + */ +template +class PardisoLU : public PardisoImpl< PardisoLU > +{ + protected: + typedef PardisoImpl< PardisoLU > Base; + typedef typename Base::Scalar Scalar; + typedef typename Base::RealScalar RealScalar; + using Base::pardisoInit; + using Base::m_matrix; + friend class PardisoImpl< PardisoLU >; + + public: + + using Base::compute; + using Base::solve; + + PardisoLU() + : Base() + { + pardisoInit(Base::ScalarIsComplex ? 13 : 11); + } + + PardisoLU(const MatrixType& matrix) + : Base() + { + pardisoInit(Base::ScalarIsComplex ? 13 : 11); + compute(matrix); + } + protected: + void getMatrix(const MatrixType& matrix) + { + m_matrix = matrix; + } + + private: + PardisoLU(PardisoLU& ) {} +}; + +/** \ingroup PardisoSupport_Module + * \class PardisoLLT + * \brief A sparse direct Cholesky (LLT) factorization and solver based on the PARDISO library + * + * This class allows to solve for A.X = B sparse linear problems via a LL^T Cholesky factorization + * using the Intel MKL PARDISO library. The sparse matrix A must be selfajoint and positive definite. + * The vectors or matrices X and B can be either dense or sparse. + * + * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * \tparam UpLo can be any bitwise combination of Upper, Lower. The default is Upper, meaning only the upper triangular part has to be used. + * Upper|Lower can be used to tell both triangular parts can be used as input. + * + * \sa \ref TutorialSparseDirectSolvers + */ +template +class PardisoLLT : public PardisoImpl< PardisoLLT > +{ + protected: + typedef PardisoImpl< PardisoLLT > Base; + typedef typename Base::Scalar Scalar; + typedef typename Base::Index Index; + typedef typename Base::RealScalar RealScalar; + using Base::pardisoInit; + using Base::m_matrix; + friend class PardisoImpl< PardisoLLT >; + + public: + + enum { UpLo = _UpLo }; + using Base::compute; + using Base::solve; + + PardisoLLT() + : Base() + { + pardisoInit(Base::ScalarIsComplex ? 4 : 2); + } + + PardisoLLT(const MatrixType& matrix) + : Base() + { + pardisoInit(Base::ScalarIsComplex ? 4 : 2); + compute(matrix); + } + + protected: + + void getMatrix(const MatrixType& matrix) + { + // PARDISO supports only upper, row-major matrices + PermutationMatrix p_null; + m_matrix.resize(matrix.rows(), matrix.cols()); + m_matrix.template selfadjointView() = matrix.template selfadjointView().twistedBy(p_null); + } + + private: + PardisoLLT(PardisoLLT& ) {} +}; + +/** \ingroup PardisoSupport_Module + * \class PardisoLDLT + * \brief A sparse direct Cholesky (LDLT) factorization and solver based on the PARDISO library + * + * This class allows to solve for A.X = B sparse linear problems via a LDL^T Cholesky factorization + * using the Intel MKL PARDISO library. The sparse matrix A is assumed to be selfajoint and positive definite. + * For complex matrices, A can also be symmetric only, see the \a Options template parameter. + * The vectors or matrices X and B can be either dense or sparse. + * + * \tparam MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * \tparam Options can be any bitwise combination of Upper, Lower, and Symmetric. The default is Upper, meaning only the upper triangular part has to be used. + * Symmetric can be used for symmetric, non-selfadjoint complex matrices, the default being to assume a selfadjoint matrix. + * Upper|Lower can be used to tell both triangular parts can be used as input. + * + * \sa \ref TutorialSparseDirectSolvers + */ +template +class PardisoLDLT : public PardisoImpl< PardisoLDLT > +{ + protected: + typedef PardisoImpl< PardisoLDLT > Base; + typedef typename Base::Scalar Scalar; + typedef typename Base::Index Index; + typedef typename Base::RealScalar RealScalar; + using Base::pardisoInit; + using Base::m_matrix; + friend class PardisoImpl< PardisoLDLT >; + + public: + + using Base::compute; + using Base::solve; + enum { UpLo = Options&(Upper|Lower) }; + + PardisoLDLT() + : Base() + { + pardisoInit(Base::ScalarIsComplex ? ( bool(Options&Symmetric) ? 6 : -4 ) : -2); + } + + PardisoLDLT(const MatrixType& matrix) + : Base() + { + pardisoInit(Base::ScalarIsComplex ? ( bool(Options&Symmetric) ? 6 : -4 ) : -2); + compute(matrix); + } + + void getMatrix(const MatrixType& matrix) + { + // PARDISO supports only upper, row-major matrices + PermutationMatrix p_null; + m_matrix.resize(matrix.rows(), matrix.cols()); + m_matrix.template selfadjointView() = matrix.template selfadjointView().twistedBy(p_null); + } + + private: + PardisoLDLT(PardisoLDLT& ) {} +}; + +namespace internal { + +template +struct solve_retval, Rhs> + : solve_retval_base, Rhs> +{ + typedef PardisoImpl<_Derived> Dec; + EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec()._solve(rhs(),dst); + } +}; + +template +struct sparse_solve_retval, Rhs> + : sparse_solve_retval_base, Rhs> +{ + typedef PardisoImpl Dec; + EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec().derived()._solve_sparse(rhs(),dst); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_PARDISOSUPPORT_H diff --git a/extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR.h b/extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR.h index f04c6038d6a..2daa23cc354 100644 --- a/extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR.h +++ b/extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR.h @@ -4,28 +4,15 @@ // Copyright (C) 2008-2009 Gael Guennebaud // Copyright (C) 2009 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_COLPIVOTINGHOUSEHOLDERQR_H #define EIGEN_COLPIVOTINGHOUSEHOLDERQR_H +namespace Eigen { + /** \ingroup QR_Module * * \class ColPivHouseholderQR @@ -528,5 +515,6 @@ MatrixBase::colPivHouseholderQr() const return ColPivHouseholderQR(eval()); } +} // end namespace Eigen #endif // EIGEN_COLPIVOTINGHOUSEHOLDERQR_H diff --git a/extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR_MKL.h b/extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR_MKL.h new file mode 100644 index 00000000000..745ecf8be98 --- /dev/null +++ b/extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR_MKL.h @@ -0,0 +1,98 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * Householder QR decomposition of a matrix with column pivoting based on + * LAPACKE_?geqp3 function. + ******************************************************************************** +*/ + +#ifndef EIGEN_COLPIVOTINGHOUSEHOLDERQR_MKL_H +#define EIGEN_COLPIVOTINGHOUSEHOLDERQR_MKL_H + +#include "Eigen/src/Core/util/MKL_support.h" + +namespace Eigen { + +/** \internal Specialization for the data types supported by MKL */ + +#define EIGEN_MKL_QR_COLPIV(EIGTYPE, MKLTYPE, MKLPREFIX, EIGCOLROW, MKLCOLROW) \ +template<> inline\ +ColPivHouseholderQR >& \ +ColPivHouseholderQR >::compute( \ + const Matrix& matrix) \ +\ +{ \ + typedef Matrix MatrixType; \ + typedef MatrixType::Scalar Scalar; \ + typedef MatrixType::RealScalar RealScalar; \ + Index rows = matrix.rows();\ + Index cols = matrix.cols();\ + Index size = matrix.diagonalSize();\ +\ + m_qr = matrix;\ + m_hCoeffs.resize(size);\ +\ + m_colsTranspositions.resize(cols);\ + /*Index number_of_transpositions = 0;*/ \ +\ + m_nonzero_pivots = 0; \ + m_maxpivot = RealScalar(0);\ + m_colsPermutation.resize(cols); \ + m_colsPermutation.indices().setZero(); \ +\ + lapack_int lda = m_qr.outerStride(), i; \ + lapack_int matrix_order = MKLCOLROW; \ + LAPACKE_##MKLPREFIX##geqp3( matrix_order, rows, cols, (MKLTYPE*)m_qr.data(), lda, (lapack_int*)m_colsPermutation.indices().data(), (MKLTYPE*)m_hCoeffs.data()); \ + m_isInitialized = true; \ + m_maxpivot=m_qr.diagonal().cwiseAbs().maxCoeff(); \ + m_hCoeffs.adjointInPlace(); \ + RealScalar premultiplied_threshold = internal::abs(m_maxpivot) * threshold(); \ + lapack_int *perm = m_colsPermutation.indices().data(); \ + for(i=0;i premultiplied_threshold);\ + } \ + for(i=0;i // Copyright (C) 2009 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H #define EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H +namespace Eigen { + +namespace internal { + +template struct FullPivHouseholderQRMatrixQReturnType; + +template +struct traits > +{ + typedef typename MatrixType::PlainObject ReturnType; +}; + +} + /** \ingroup QR_Module * * \class FullPivHouseholderQR @@ -62,7 +61,7 @@ template class FullPivHouseholderQR typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; typedef typename MatrixType::Index Index; - typedef Matrix MatrixQType; + typedef internal::FullPivHouseholderQRMatrixQReturnType MatrixQReturnType; typedef typename internal::plain_diag_type::type HCoeffsType; typedef Matrix IntRowVectorType; typedef PermutationMatrix PermutationType; @@ -139,7 +138,9 @@ template class FullPivHouseholderQR return internal::solve_retval(*this, b.derived()); } - MatrixQType matrixQ(void) const; + /** \returns Expression object representing the matrix Q + */ + MatrixQReturnType matrixQ(void) const; /** \returns a reference to the matrix where the Householder QR decomposition is stored */ @@ -508,28 +509,73 @@ struct solve_retval, Rhs> } }; +/** \ingroup QR_Module + * + * \brief Expression type for return value of FullPivHouseholderQR::matrixQ() + * + * \tparam MatrixType type of underlying dense matrix + */ +template struct FullPivHouseholderQRMatrixQReturnType + : public ReturnByValue > +{ +public: + typedef typename MatrixType::Index Index; + typedef typename internal::plain_col_type::type IntColVectorType; + typedef typename internal::plain_diag_type::type HCoeffsType; + typedef Matrix WorkVectorType; + + FullPivHouseholderQRMatrixQReturnType(const MatrixType& qr, + const HCoeffsType& hCoeffs, + const IntColVectorType& rowsTranspositions) + : m_qr(qr), + m_hCoeffs(hCoeffs), + m_rowsTranspositions(rowsTranspositions) + {} + + template + void evalTo(ResultType& result) const + { + const Index rows = m_qr.rows(); + WorkVectorType workspace(rows); + evalTo(result, workspace); + } + + template + void evalTo(ResultType& result, WorkVectorType& workspace) const + { + // compute the product H'_0 H'_1 ... H'_n-1, + // where H_k is the k-th Householder transformation I - h_k v_k v_k' + // and v_k is the k-th Householder vector [1,m_qr(k+1,k), m_qr(k+2,k), ...] + const Index rows = m_qr.rows(); + const Index cols = m_qr.cols(); + const Index size = (std::min)(rows, cols); + workspace.resize(rows); + result.setIdentity(rows, rows); + for (Index k = size-1; k >= 0; k--) + { + result.block(k, k, rows-k, rows-k) + .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), internal::conj(m_hCoeffs.coeff(k)), &workspace.coeffRef(k)); + result.row(k).swap(result.row(m_rowsTranspositions.coeff(k))); + } + } + + Index rows() const { return m_qr.rows(); } + Index cols() const { return m_qr.rows(); } + +protected: + typename MatrixType::Nested m_qr; + typename HCoeffsType::Nested m_hCoeffs; + typename IntColVectorType::Nested m_rowsTranspositions; +}; + } // end namespace internal -/** \returns the matrix Q */ template -typename FullPivHouseholderQR::MatrixQType FullPivHouseholderQR::matrixQ() const +inline typename FullPivHouseholderQR::MatrixQReturnType FullPivHouseholderQR::matrixQ() const { eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); - // compute the product H'_0 H'_1 ... H'_n-1, - // where H_k is the k-th Householder transformation I - h_k v_k v_k' - // and v_k is the k-th Householder vector [1,m_qr(k+1,k), m_qr(k+2,k), ...] - Index rows = m_qr.rows(); - Index cols = m_qr.cols(); - Index size = (std::min)(rows,cols); - MatrixQType res = MatrixQType::Identity(rows, rows); - Matrix temp(rows); - for (Index k = size-1; k >= 0; k--) - { - res.block(k, k, rows-k, rows-k) - .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), internal::conj(m_hCoeffs.coeff(k)), &temp.coeffRef(k)); - res.row(k).swap(res.row(m_rows_transpositions.coeff(k))); - } - return res; + return MatrixQReturnType(m_qr, m_hCoeffs, m_rows_transpositions); } /** \return the full-pivoting Householder QR decomposition of \c *this. @@ -543,4 +589,6 @@ MatrixBase::fullPivHouseholderQr() const return FullPivHouseholderQR(eval()); } +} // end namespace Eigen + #endif // EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H diff --git a/extern/Eigen3/Eigen/src/QR/HouseholderQR.h b/extern/Eigen3/Eigen/src/QR/HouseholderQR.h index 9ee96de2680..5bcb32c1e18 100644 --- a/extern/Eigen3/Eigen/src/QR/HouseholderQR.h +++ b/extern/Eigen3/Eigen/src/QR/HouseholderQR.h @@ -5,28 +5,15 @@ // Copyright (C) 2009 Benoit Jacob // Copyright (C) 2010 Vincent Lejeune // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_QR_H #define EIGEN_QR_H +namespace Eigen { + /** \ingroup QR_Module * * @@ -351,5 +338,6 @@ MatrixBase::householderQr() const return HouseholderQR(eval()); } +} // end namespace Eigen #endif // EIGEN_QR_H diff --git a/extern/Eigen3/Eigen/src/QR/HouseholderQR_MKL.h b/extern/Eigen3/Eigen/src/QR/HouseholderQR_MKL.h new file mode 100644 index 00000000000..5313de604d2 --- /dev/null +++ b/extern/Eigen3/Eigen/src/QR/HouseholderQR_MKL.h @@ -0,0 +1,69 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * Householder QR decomposition of a matrix w/o pivoting based on + * LAPACKE_?geqrf function. + ******************************************************************************** +*/ + +#ifndef EIGEN_QR_MKL_H +#define EIGEN_QR_MKL_H + +#include "Eigen/src/Core/util/MKL_support.h" + +namespace Eigen { + +namespace internal { + +/** \internal Specialization for the data types supported by MKL */ + +#define EIGEN_MKL_QR_NOPIV(EIGTYPE, MKLTYPE, MKLPREFIX) \ +template \ +void householder_qr_inplace_blocked(MatrixQR& mat, HCoeffs& hCoeffs, \ + typename MatrixQR::Index maxBlockSize=32, \ + EIGTYPE* tempData = 0) \ +{ \ + lapack_int m = mat.rows(); \ + lapack_int n = mat.cols(); \ + lapack_int lda = mat.outerStride(); \ + lapack_int matrix_order = (MatrixQR::IsRowMajor) ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; \ + LAPACKE_##MKLPREFIX##geqrf( matrix_order, m, n, (MKLTYPE*)mat.data(), lda, (MKLTYPE*)hCoeffs.data()); \ + hCoeffs.adjointInPlace(); \ +\ +} + +EIGEN_MKL_QR_NOPIV(double, double, d) +EIGEN_MKL_QR_NOPIV(float, float, s) +EIGEN_MKL_QR_NOPIV(dcomplex, MKL_Complex16, z) +EIGEN_MKL_QR_NOPIV(scomplex, MKL_Complex8, c) + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_QR_MKL_H diff --git a/extern/Eigen3/Eigen/src/SVD/JacobiSVD.h b/extern/Eigen3/Eigen/src/SVD/JacobiSVD.h index 3c423095c31..a7dbf073766 100644 --- a/extern/Eigen3/Eigen/src/SVD/JacobiSVD.h +++ b/extern/Eigen3/Eigen/src/SVD/JacobiSVD.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009-2010 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_JACOBISVD_H #define EIGEN_JACOBISVD_H +namespace Eigen { + namespace internal { // forward declaration (needed by ICC) // the empty body is required by MSVC @@ -61,9 +48,12 @@ template struct qr_preconditioner_impl {}; template -struct qr_preconditioner_impl +class qr_preconditioner_impl { - static bool run(JacobiSVD&, const MatrixType&) +public: + typedef typename MatrixType::Index Index; + void allocate(const JacobiSVD&) {} + bool run(JacobiSVD&, const MatrixType&) { return false; } @@ -72,134 +62,279 @@ struct qr_preconditioner_impl /*** preconditioner using FullPivHouseholderQR ***/ template -struct qr_preconditioner_impl +class qr_preconditioner_impl { - static bool run(JacobiSVD& svd, const MatrixType& matrix) +public: + typedef typename MatrixType::Index Index; + typedef typename MatrixType::Scalar Scalar; + enum + { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime + }; + typedef Matrix WorkspaceType; + + void allocate(const JacobiSVD& svd) + { + if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols()) + { + m_qr = FullPivHouseholderQR(svd.rows(), svd.cols()); + } + if (svd.m_computeFullU) m_workspace.resize(svd.rows()); + } + + bool run(JacobiSVD& svd, const MatrixType& matrix) { if(matrix.rows() > matrix.cols()) { - FullPivHouseholderQR qr(matrix); - svd.m_workMatrix = qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView(); - if(svd.m_computeFullU) svd.m_matrixU = qr.matrixQ(); - if(svd.computeV()) svd.m_matrixV = qr.colsPermutation(); + m_qr.compute(matrix); + svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView(); + if(svd.m_computeFullU) m_qr.matrixQ().evalTo(svd.m_matrixU, m_workspace); + if(svd.computeV()) svd.m_matrixV = m_qr.colsPermutation(); return true; } return false; } +private: + FullPivHouseholderQR m_qr; + WorkspaceType m_workspace; }; template -struct qr_preconditioner_impl +class qr_preconditioner_impl { - static bool run(JacobiSVD& svd, const MatrixType& matrix) +public: + typedef typename MatrixType::Index Index; + typedef typename MatrixType::Scalar Scalar; + enum + { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime, + MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, + Options = MatrixType::Options + }; + typedef Matrix + TransposeTypeWithSameStorageOrder; + + void allocate(const JacobiSVD& svd) + { + if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols()) + { + m_qr = FullPivHouseholderQR(svd.cols(), svd.rows()); + } + m_adjoint.resize(svd.cols(), svd.rows()); + if (svd.m_computeFullV) m_workspace.resize(svd.cols()); + } + + bool run(JacobiSVD& svd, const MatrixType& matrix) { if(matrix.cols() > matrix.rows()) { - typedef Matrix - TransposeTypeWithSameStorageOrder; - FullPivHouseholderQR qr(matrix.adjoint()); - svd.m_workMatrix = qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView().adjoint(); - if(svd.m_computeFullV) svd.m_matrixV = qr.matrixQ(); - if(svd.computeU()) svd.m_matrixU = qr.colsPermutation(); + m_adjoint = matrix.adjoint(); + m_qr.compute(m_adjoint); + svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView().adjoint(); + if(svd.m_computeFullV) m_qr.matrixQ().evalTo(svd.m_matrixV, m_workspace); + if(svd.computeU()) svd.m_matrixU = m_qr.colsPermutation(); return true; } else return false; } +private: + FullPivHouseholderQR m_qr; + TransposeTypeWithSameStorageOrder m_adjoint; + typename internal::plain_row_type::type m_workspace; }; /*** preconditioner using ColPivHouseholderQR ***/ template -struct qr_preconditioner_impl +class qr_preconditioner_impl { - static bool run(JacobiSVD& svd, const MatrixType& matrix) +public: + typedef typename MatrixType::Index Index; + + void allocate(const JacobiSVD& svd) + { + if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols()) + { + m_qr = ColPivHouseholderQR(svd.rows(), svd.cols()); + } + if (svd.m_computeFullU) m_workspace.resize(svd.rows()); + else if (svd.m_computeThinU) m_workspace.resize(svd.cols()); + } + + bool run(JacobiSVD& svd, const MatrixType& matrix) { if(matrix.rows() > matrix.cols()) { - ColPivHouseholderQR qr(matrix); - svd.m_workMatrix = qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView(); - if(svd.m_computeFullU) svd.m_matrixU = qr.householderQ(); - else if(svd.m_computeThinU) { + m_qr.compute(matrix); + svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView(); + if(svd.m_computeFullU) m_qr.householderQ().evalTo(svd.m_matrixU, m_workspace); + else if(svd.m_computeThinU) + { svd.m_matrixU.setIdentity(matrix.rows(), matrix.cols()); - qr.householderQ().applyThisOnTheLeft(svd.m_matrixU); + m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixU, m_workspace); } - if(svd.computeV()) svd.m_matrixV = qr.colsPermutation(); + if(svd.computeV()) svd.m_matrixV = m_qr.colsPermutation(); return true; } return false; } + +private: + ColPivHouseholderQR m_qr; + typename internal::plain_col_type::type m_workspace; }; template -struct qr_preconditioner_impl +class qr_preconditioner_impl { - static bool run(JacobiSVD& svd, const MatrixType& matrix) +public: + typedef typename MatrixType::Index Index; + typedef typename MatrixType::Scalar Scalar; + enum + { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime, + MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, + Options = MatrixType::Options + }; + + typedef Matrix + TransposeTypeWithSameStorageOrder; + + void allocate(const JacobiSVD& svd) + { + if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols()) + { + m_qr = ColPivHouseholderQR(svd.cols(), svd.rows()); + } + if (svd.m_computeFullV) m_workspace.resize(svd.cols()); + else if (svd.m_computeThinV) m_workspace.resize(svd.rows()); + m_adjoint.resize(svd.cols(), svd.rows()); + } + + bool run(JacobiSVD& svd, const MatrixType& matrix) { if(matrix.cols() > matrix.rows()) { - typedef Matrix - TransposeTypeWithSameStorageOrder; - ColPivHouseholderQR qr(matrix.adjoint()); - svd.m_workMatrix = qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView().adjoint(); - if(svd.m_computeFullV) svd.m_matrixV = qr.householderQ(); - else if(svd.m_computeThinV) { + m_adjoint = matrix.adjoint(); + m_qr.compute(m_adjoint); + + svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView().adjoint(); + if(svd.m_computeFullV) m_qr.householderQ().evalTo(svd.m_matrixV, m_workspace); + else if(svd.m_computeThinV) + { svd.m_matrixV.setIdentity(matrix.cols(), matrix.rows()); - qr.householderQ().applyThisOnTheLeft(svd.m_matrixV); + m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixV, m_workspace); } - if(svd.computeU()) svd.m_matrixU = qr.colsPermutation(); + if(svd.computeU()) svd.m_matrixU = m_qr.colsPermutation(); return true; } else return false; } + +private: + ColPivHouseholderQR m_qr; + TransposeTypeWithSameStorageOrder m_adjoint; + typename internal::plain_row_type::type m_workspace; }; /*** preconditioner using HouseholderQR ***/ template -struct qr_preconditioner_impl +class qr_preconditioner_impl { - static bool run(JacobiSVD& svd, const MatrixType& matrix) +public: + typedef typename MatrixType::Index Index; + + void allocate(const JacobiSVD& svd) + { + if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols()) + { + m_qr = HouseholderQR(svd.rows(), svd.cols()); + } + if (svd.m_computeFullU) m_workspace.resize(svd.rows()); + else if (svd.m_computeThinU) m_workspace.resize(svd.cols()); + } + + bool run(JacobiSVD& svd, const MatrixType& matrix) { if(matrix.rows() > matrix.cols()) { - HouseholderQR qr(matrix); - svd.m_workMatrix = qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView(); - if(svd.m_computeFullU) svd.m_matrixU = qr.householderQ(); - else if(svd.m_computeThinU) { + m_qr.compute(matrix); + svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView(); + if(svd.m_computeFullU) m_qr.householderQ().evalTo(svd.m_matrixU, m_workspace); + else if(svd.m_computeThinU) + { svd.m_matrixU.setIdentity(matrix.rows(), matrix.cols()); - qr.householderQ().applyThisOnTheLeft(svd.m_matrixU); + m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixU, m_workspace); } if(svd.computeV()) svd.m_matrixV.setIdentity(matrix.cols(), matrix.cols()); return true; } return false; } +private: + HouseholderQR m_qr; + typename internal::plain_col_type::type m_workspace; }; template -struct qr_preconditioner_impl +class qr_preconditioner_impl { - static bool run(JacobiSVD& svd, const MatrixType& matrix) +public: + typedef typename MatrixType::Index Index; + typedef typename MatrixType::Scalar Scalar; + enum + { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime, + MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, + Options = MatrixType::Options + }; + + typedef Matrix + TransposeTypeWithSameStorageOrder; + + void allocate(const JacobiSVD& svd) + { + if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols()) + { + m_qr = HouseholderQR(svd.cols(), svd.rows()); + } + if (svd.m_computeFullV) m_workspace.resize(svd.cols()); + else if (svd.m_computeThinV) m_workspace.resize(svd.rows()); + m_adjoint.resize(svd.cols(), svd.rows()); + } + + bool run(JacobiSVD& svd, const MatrixType& matrix) { if(matrix.cols() > matrix.rows()) { - typedef Matrix - TransposeTypeWithSameStorageOrder; - HouseholderQR qr(matrix.adjoint()); - svd.m_workMatrix = qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView().adjoint(); - if(svd.m_computeFullV) svd.m_matrixV = qr.householderQ(); - else if(svd.m_computeThinV) { + m_adjoint = matrix.adjoint(); + m_qr.compute(m_adjoint); + + svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView().adjoint(); + if(svd.m_computeFullV) m_qr.householderQ().evalTo(svd.m_matrixV, m_workspace); + else if(svd.m_computeThinV) + { svd.m_matrixV.setIdentity(matrix.cols(), matrix.rows()); - qr.householderQ().applyThisOnTheLeft(svd.m_matrixV); + m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixV, m_workspace); } if(svd.computeU()) svd.m_matrixU.setIdentity(matrix.rows(), matrix.rows()); return true; } else return false; } + +private: + HouseholderQR m_qr; + TransposeTypeWithSameStorageOrder m_adjoint; + typename internal::plain_row_type::type m_workspace; }; /*** 2x2 SVD implementation @@ -316,7 +451,7 @@ void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q, * Here's an example demonstrating basic usage: * \include JacobiSVD_basic.cpp * Output: \verbinclude JacobiSVD_basic.out - * + * * This JacobiSVD class is a two-sided Jacobi R-SVD decomposition, ensuring optimal reliability and accuracy. The downside is that it's slower than * bidiagonalizing SVD algorithms for large square matrices; however its complexity is still \f$ O(n^2p) \f$ where \a n is the smaller dimension and * \a p is the greater dimension, meaning that it is still of the same order of complexity as the faster bidiagonalizing R-SVD algorithms. @@ -324,7 +459,7 @@ void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q, * * If the input matrix has inf or nan coefficients, the result of the computation is undefined, but the computation is guaranteed to * terminate in finite (and reasonable) time. - * + * * The possible values for QRPreconditioner are: * \li ColPivHouseholderQRPreconditioner is the default. In practice it's very safe. It uses column-pivoting QR. * \li FullPivHouseholderQRPreconditioner, is the safest and slowest. It uses full-pivoting QR. @@ -494,7 +629,7 @@ template class JacobiSVD * \param b the right-hand-side of the equation to solve. * * \note Solving requires both U and V to be computed. Thin U and V are enough, there is no need for full U or V. - * + * * \note SVD solving is implicitly least-squares. Thus, this method serves both purposes of exact solving and least-squares solving. * In other words, the returned solution is guaranteed to minimize the Euclidean norm \f$ \Vert A x - b \Vert \f$. */ @@ -535,6 +670,9 @@ template class JacobiSVD friend struct internal::svd_precondition_2x2_block_to_be_real; template friend struct internal::qr_preconditioner_impl; + + internal::qr_preconditioner_impl m_qr_precond_morecols; + internal::qr_preconditioner_impl m_qr_precond_morerows; }; template @@ -578,6 +716,9 @@ void JacobiSVD::allocate(Index rows, Index cols, u : m_computeThinV ? m_diagSize : 0); m_workMatrix.resize(m_diagSize, m_diagSize); + + if(m_cols>m_rows) m_qr_precond_morecols.allocate(*this); + if(m_rows>m_cols) m_qr_precond_morerows.allocate(*this); } template @@ -595,8 +736,7 @@ JacobiSVD::compute(const MatrixType& matrix, unsig /*** step 1. The R-SVD step: we use a QR decomposition to reduce to the case of a square matrix */ - if(!internal::qr_preconditioner_impl::run(*this, matrix) - && !internal::qr_preconditioner_impl::run(*this, matrix)) + if(!m_qr_precond_morecols.run(*this, matrix) && !m_qr_precond_morerows.run(*this, matrix)) { m_workMatrix = matrix.block(0,0,m_diagSize,m_diagSize); if(m_computeFullU) m_matrixU.setIdentity(m_rows,m_rows); @@ -722,6 +862,6 @@ MatrixBase::jacobiSvd(unsigned int computationOptions) const return JacobiSVD(*this, computationOptions); } - +} // end namespace Eigen #endif // EIGEN_JACOBISVD_H diff --git a/extern/Eigen3/Eigen/src/SVD/JacobiSVD_MKL.h b/extern/Eigen3/Eigen/src/SVD/JacobiSVD_MKL.h new file mode 100644 index 00000000000..4d479f6b26e --- /dev/null +++ b/extern/Eigen3/Eigen/src/SVD/JacobiSVD_MKL.h @@ -0,0 +1,92 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * Singular Value Decomposition - SVD. + ******************************************************************************** +*/ + +#ifndef EIGEN_JACOBISVD_MKL_H +#define EIGEN_JACOBISVD_MKL_H + +#include "Eigen/src/Core/util/MKL_support.h" + +namespace Eigen { + +/** \internal Specialization for the data types supported by MKL */ + +#define EIGEN_MKL_SVD(EIGTYPE, MKLTYPE, MKLRTYPE, MKLPREFIX, EIGCOLROW, MKLCOLROW) \ +template<> inline\ +JacobiSVD, ColPivHouseholderQRPreconditioner>& \ +JacobiSVD, ColPivHouseholderQRPreconditioner>::compute(const Matrix& matrix, unsigned int computationOptions) \ +{ \ + typedef Matrix MatrixType; \ + typedef MatrixType::Scalar Scalar; \ + typedef MatrixType::RealScalar RealScalar; \ + allocate(matrix.rows(), matrix.cols(), computationOptions); \ +\ + /*const RealScalar precision = RealScalar(2) * NumTraits::epsilon();*/ \ + m_nonzeroSingularValues = m_diagSize; \ +\ + lapack_int lda = matrix.outerStride(), ldu, ldvt; \ + lapack_int matrix_order = MKLCOLROW; \ + char jobu, jobvt; \ + MKLTYPE *u, *vt, dummy; \ + jobu = (m_computeFullU) ? 'A' : (m_computeThinU) ? 'S' : 'N'; \ + jobvt = (m_computeFullV) ? 'A' : (m_computeThinV) ? 'S' : 'N'; \ + if (computeU()) { \ + ldu = m_matrixU.outerStride(); \ + u = (MKLTYPE*)m_matrixU.data(); \ + } else { ldu=1; u=&dummy; }\ + MatrixType localV; \ + ldvt = (m_computeFullV) ? m_cols : (m_computeThinV) ? m_diagSize : 1; \ + if (computeV()) { \ + localV.resize(ldvt, m_cols); \ + vt = (MKLTYPE*)localV.data(); \ + } else { ldvt=1; vt=&dummy; }\ + Matrix superb; superb.resize(m_diagSize, 1); \ + MatrixType m_temp; m_temp = matrix; \ + LAPACKE_##MKLPREFIX##gesvd( matrix_order, jobu, jobvt, m_rows, m_cols, (MKLTYPE*)m_temp.data(), lda, (MKLRTYPE*)m_singularValues.data(), u, ldu, vt, ldvt, superb.data()); \ + if (computeV()) m_matrixV = localV.adjoint(); \ + /* for(int i=0;i // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_BIDIAGONALIZATION_H #define EIGEN_BIDIAGONALIZATION_H +namespace Eigen { + namespace internal { // UpperBidiagonalization will probably be replaced by a Bidiagonalization class, don't want to make it stable API. // At the same time, it's useful to keep for now as it's about the only thing that is testing the BandMatrix class. @@ -156,4 +143,6 @@ MatrixBase::bidiagonalization() const } // end namespace internal +} // end namespace Eigen + #endif // EIGEN_BIDIAGONALIZATION_H diff --git a/extern/Eigen3/Eigen/src/Sparse/AmbiVector.h b/extern/Eigen3/Eigen/src/Sparse/AmbiVector.h deleted file mode 100644 index 2ea8ba3096b..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/AmbiVector.h +++ /dev/null @@ -1,379 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_AMBIVECTOR_H -#define EIGEN_AMBIVECTOR_H - -/** \internal - * Hybrid sparse/dense vector class designed for intensive read-write operations. - * - * See BasicSparseLLT and SparseProduct for usage examples. - */ -template -class AmbiVector -{ - public: - typedef _Scalar Scalar; - typedef _Index Index; - typedef typename NumTraits::Real RealScalar; - - AmbiVector(Index size) - : m_buffer(0), m_zero(0), m_size(0), m_allocatedSize(0), m_allocatedElements(0), m_mode(-1) - { - resize(size); - } - - void init(double estimatedDensity); - void init(int mode); - - Index nonZeros() const; - - /** Specifies a sub-vector to work on */ - void setBounds(Index start, Index end) { m_start = start; m_end = end; } - - void setZero(); - - void restart(); - Scalar& coeffRef(Index i); - Scalar& coeff(Index i); - - class Iterator; - - ~AmbiVector() { delete[] m_buffer; } - - void resize(Index size) - { - if (m_allocatedSize < size) - reallocate(size); - m_size = size; - } - - Index size() const { return m_size; } - - protected: - - void reallocate(Index size) - { - // if the size of the matrix is not too large, let's allocate a bit more than needed such - // that we can handle dense vector even in sparse mode. - delete[] m_buffer; - if (size<1000) - { - Index allocSize = (size * sizeof(ListEl))/sizeof(Scalar); - m_allocatedElements = (allocSize*sizeof(Scalar))/sizeof(ListEl); - m_buffer = new Scalar[allocSize]; - } - else - { - m_allocatedElements = (size*sizeof(Scalar))/sizeof(ListEl); - m_buffer = new Scalar[size]; - } - m_size = size; - m_start = 0; - m_end = m_size; - } - - void reallocateSparse() - { - Index copyElements = m_allocatedElements; - m_allocatedElements = (std::min)(Index(m_allocatedElements*1.5),m_size); - Index allocSize = m_allocatedElements * sizeof(ListEl); - allocSize = allocSize/sizeof(Scalar) + (allocSize%sizeof(Scalar)>0?1:0); - Scalar* newBuffer = new Scalar[allocSize]; - memcpy(newBuffer, m_buffer, copyElements * sizeof(ListEl)); - delete[] m_buffer; - m_buffer = newBuffer; - } - - protected: - // element type of the linked list - struct ListEl - { - Index next; - Index index; - Scalar value; - }; - - // used to store data in both mode - Scalar* m_buffer; - Scalar m_zero; - Index m_size; - Index m_start; - Index m_end; - Index m_allocatedSize; - Index m_allocatedElements; - Index m_mode; - - // linked list mode - Index m_llStart; - Index m_llCurrent; - Index m_llSize; -}; - -/** \returns the number of non zeros in the current sub vector */ -template -_Index AmbiVector<_Scalar,_Index>::nonZeros() const -{ - if (m_mode==IsSparse) - return m_llSize; - else - return m_end - m_start; -} - -template -void AmbiVector<_Scalar,_Index>::init(double estimatedDensity) -{ - if (estimatedDensity>0.1) - init(IsDense); - else - init(IsSparse); -} - -template -void AmbiVector<_Scalar,_Index>::init(int mode) -{ - m_mode = mode; - if (m_mode==IsSparse) - { - m_llSize = 0; - m_llStart = -1; - } -} - -/** Must be called whenever we might perform a write access - * with an index smaller than the previous one. - * - * Don't worry, this function is extremely cheap. - */ -template -void AmbiVector<_Scalar,_Index>::restart() -{ - m_llCurrent = m_llStart; -} - -/** Set all coefficients of current subvector to zero */ -template -void AmbiVector<_Scalar,_Index>::setZero() -{ - if (m_mode==IsDense) - { - for (Index i=m_start; i -_Scalar& AmbiVector<_Scalar,_Index>::coeffRef(_Index i) -{ - if (m_mode==IsDense) - return m_buffer[i]; - else - { - ListEl* EIGEN_RESTRICT llElements = reinterpret_cast(m_buffer); - // TODO factorize the following code to reduce code generation - eigen_assert(m_mode==IsSparse); - if (m_llSize==0) - { - // this is the first element - m_llStart = 0; - m_llCurrent = 0; - ++m_llSize; - llElements[0].value = Scalar(0); - llElements[0].index = i; - llElements[0].next = -1; - return llElements[0].value; - } - else if (i=llElements[m_llCurrent].index && "you must call restart() before inserting an element with lower or equal index"); - while (nextel >= 0 && llElements[nextel].index<=i) - { - m_llCurrent = nextel; - nextel = llElements[nextel].next; - } - - if (llElements[m_llCurrent].index==i) - { - // the coefficient already exists and we found it ! - return llElements[m_llCurrent].value; - } - else - { - if (m_llSize>=m_allocatedElements) - { - reallocateSparse(); - llElements = reinterpret_cast(m_buffer); - } - eigen_internal_assert(m_llSize -_Scalar& AmbiVector<_Scalar,_Index>::coeff(_Index i) -{ - if (m_mode==IsDense) - return m_buffer[i]; - else - { - ListEl* EIGEN_RESTRICT llElements = reinterpret_cast(m_buffer); - eigen_assert(m_mode==IsSparse); - if ((m_llSize==0) || (i= 0 && llElements[elid].index -class AmbiVector<_Scalar,_Index>::Iterator -{ - public: - typedef _Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - - /** Default constructor - * \param vec the vector on which we iterate - * \param epsilon the minimal value used to prune zero coefficients. - * In practice, all coefficients having a magnitude smaller than \a epsilon - * are skipped. - */ - Iterator(const AmbiVector& vec, RealScalar epsilon = RealScalar(0.1)*NumTraits::dummy_precision()) - : m_vector(vec) - { - m_epsilon = epsilon; - m_isDense = m_vector.m_mode==IsDense; - if (m_isDense) - { - m_currentEl = 0; // this is to avoid a compilation warning - m_cachedValue = 0; // this is to avoid a compilation warning - m_cachedIndex = m_vector.m_start-1; - ++(*this); - } - else - { - ListEl* EIGEN_RESTRICT llElements = reinterpret_cast(m_vector.m_buffer); - m_currentEl = m_vector.m_llStart; - while (m_currentEl>=0 && internal::abs(llElements[m_currentEl].value)=0; } - - Iterator& operator++() - { - if (m_isDense) - { - do { - ++m_cachedIndex; - } while (m_cachedIndex(m_vector.m_buffer); - do { - m_currentEl = llElements[m_currentEl].next; - } while (m_currentEl>=0 && internal::abs(llElements[m_currentEl].value) -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_COMPRESSED_STORAGE_H -#define EIGEN_COMPRESSED_STORAGE_H - -/** Stores a sparse set of values as a list of values and a list of indices. - * - */ -template -class CompressedStorage -{ - public: - - typedef _Scalar Scalar; - typedef _Index Index; - - protected: - - typedef typename NumTraits::Real RealScalar; - - public: - - CompressedStorage() - : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0) - {} - - CompressedStorage(size_t size) - : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0) - { - resize(size); - } - - CompressedStorage(const CompressedStorage& other) - : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0) - { - *this = other; - } - - CompressedStorage& operator=(const CompressedStorage& other) - { - resize(other.size()); - memcpy(m_values, other.m_values, m_size * sizeof(Scalar)); - memcpy(m_indices, other.m_indices, m_size * sizeof(Index)); - return *this; - } - - void swap(CompressedStorage& other) - { - std::swap(m_values, other.m_values); - std::swap(m_indices, other.m_indices); - std::swap(m_size, other.m_size); - std::swap(m_allocatedSize, other.m_allocatedSize); - } - - ~CompressedStorage() - { - delete[] m_values; - delete[] m_indices; - } - - void reserve(size_t size) - { - size_t newAllocatedSize = m_size + size; - if (newAllocatedSize > m_allocatedSize) - reallocate(newAllocatedSize); - } - - void squeeze() - { - if (m_allocatedSize>m_size) - reallocate(m_size); - } - - void resize(size_t size, float reserveSizeFactor = 0) - { - if (m_allocatedSize(m_size); - resize(m_size+1, 1); - m_values[id] = v; - m_indices[id] = i; - } - - inline size_t size() const { return m_size; } - inline size_t allocatedSize() const { return m_allocatedSize; } - inline void clear() { m_size = 0; } - - inline Scalar& value(size_t i) { return m_values[i]; } - inline const Scalar& value(size_t i) const { return m_values[i]; } - - inline Index& index(size_t i) { return m_indices[i]; } - inline const Index& index(size_t i) const { return m_indices[i]; } - - static CompressedStorage Map(Index* indices, Scalar* values, size_t size) - { - CompressedStorage res; - res.m_indices = indices; - res.m_values = values; - res.m_allocatedSize = res.m_size = size; - return res; - } - - /** \returns the largest \c k such that for all \c j in [0,k) index[\c j]\<\a key */ - inline Index searchLowerIndex(Index key) const - { - return searchLowerIndex(0, m_size, key); - } - - /** \returns the largest \c k in [start,end) such that for all \c j in [start,k) index[\c j]\<\a key */ - inline Index searchLowerIndex(size_t start, size_t end, Index key) const - { - while(end>start) - { - size_t mid = (end+start)>>1; - if (m_indices[mid](start); - } - - /** \returns the stored value at index \a key - * If the value does not exist, then the value \a defaultValue is returned without any insertion. */ - inline Scalar at(Index key, Scalar defaultValue = Scalar(0)) const - { - if (m_size==0) - return defaultValue; - else if (key==m_indices[m_size-1]) - return m_values[m_size-1]; - // ^^ optimization: let's first check if it is the last coefficient - // (very common in high level algorithms) - const size_t id = searchLowerIndex(0,m_size-1,key); - return ((id=end) - return Scalar(0); - else if (end>start && key==m_indices[end-1]) - return m_values[end-1]; - // ^^ optimization: let's first check if it is the last coefficient - // (very common in high level algorithms) - const size_t id = searchLowerIndex(start,end-1,key); - return ((id=m_size || m_indices[id]!=key) - { - resize(m_size+1,1); - for (size_t j=m_size-1; j>id; --j) - { - m_indices[j] = m_indices[j-1]; - m_values[j] = m_values[j-1]; - } - m_indices[id] = key; - m_values[id] = defaultValue; - } - return m_values[id]; - } - - void prune(Scalar reference, RealScalar epsilon = NumTraits::dummy_precision()) - { - size_t k = 0; - size_t n = size(); - for (size_t i=0; i -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_COREITERATORS_H -#define EIGEN_COREITERATORS_H - -/* This file contains the respective InnerIterator definition of the expressions defined in Eigen/Core - */ - -/** \class InnerIterator - * \brief An InnerIterator allows to loop over the element of a sparse (or dense) matrix or expression - * - * todo - */ - -// generic version for dense matrix and expressions -template class DenseBase::InnerIterator -{ - protected: - typedef typename Derived::Scalar Scalar; - typedef typename Derived::Index Index; - - enum { IsRowMajor = (Derived::Flags&RowMajorBit)==RowMajorBit }; - public: - EIGEN_STRONG_INLINE InnerIterator(const Derived& expr, Index outer) - : m_expression(expr), m_inner(0), m_outer(outer), m_end(expr.innerSize()) - {} - - EIGEN_STRONG_INLINE Scalar value() const - { - return (IsRowMajor) ? m_expression.coeff(m_outer, m_inner) - : m_expression.coeff(m_inner, m_outer); - } - - EIGEN_STRONG_INLINE InnerIterator& operator++() { m_inner++; return *this; } - - EIGEN_STRONG_INLINE Index index() const { return m_inner; } - inline Index row() const { return IsRowMajor ? m_outer : index(); } - inline Index col() const { return IsRowMajor ? index() : m_outer; } - - EIGEN_STRONG_INLINE operator bool() const { return m_inner < m_end && m_inner>=0; } - - protected: - const Derived& m_expression; - Index m_inner; - const Index m_outer; - const Index m_end; -}; - -#endif // EIGEN_COREITERATORS_H diff --git a/extern/Eigen3/Eigen/src/Sparse/DynamicSparseMatrix.h b/extern/Eigen3/Eigen/src/Sparse/DynamicSparseMatrix.h deleted file mode 100644 index 93e75f4c601..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/DynamicSparseMatrix.h +++ /dev/null @@ -1,346 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_DYNAMIC_SPARSEMATRIX_H -#define EIGEN_DYNAMIC_SPARSEMATRIX_H - -/** \class DynamicSparseMatrix - * - * \brief A sparse matrix class designed for matrix assembly purpose - * - * \param _Scalar the scalar type, i.e. the type of the coefficients - * - * Unlike SparseMatrix, this class provides a much higher degree of flexibility. In particular, it allows - * random read/write accesses in log(rho*outer_size) where \c rho is the probability that a coefficient is - * nonzero and outer_size is the number of columns if the matrix is column-major and the number of rows - * otherwise. - * - * Internally, the data are stored as a std::vector of compressed vector. The performances of random writes might - * decrease as the number of nonzeros per inner-vector increase. In practice, we observed very good performance - * till about 100 nonzeros/vector, and the performance remains relatively good till 500 nonzeros/vectors. - * - * \see SparseMatrix - */ - -namespace internal { -template -struct traits > -{ - typedef _Scalar Scalar; - typedef _Index Index; - typedef Sparse StorageKind; - typedef MatrixXpr XprKind; - enum { - RowsAtCompileTime = Dynamic, - ColsAtCompileTime = Dynamic, - MaxRowsAtCompileTime = Dynamic, - MaxColsAtCompileTime = Dynamic, - Flags = _Options | NestByRefBit | LvalueBit, - CoeffReadCost = NumTraits::ReadCost, - SupportedAccessPatterns = OuterRandomAccessPattern - }; -}; -} - -template -class DynamicSparseMatrix - : public SparseMatrixBase > -{ - public: - EIGEN_SPARSE_PUBLIC_INTERFACE(DynamicSparseMatrix) - // FIXME: why are these operator already alvailable ??? - // EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(DynamicSparseMatrix, +=) - // EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(DynamicSparseMatrix, -=) - typedef MappedSparseMatrix Map; - using Base::IsRowMajor; - using Base::operator=; - enum { - Options = _Options - }; - - protected: - - typedef DynamicSparseMatrix TransposedSparseMatrix; - - Index m_innerSize; - std::vector > m_data; - - public: - - inline Index rows() const { return IsRowMajor ? outerSize() : m_innerSize; } - inline Index cols() const { return IsRowMajor ? m_innerSize : outerSize(); } - inline Index innerSize() const { return m_innerSize; } - inline Index outerSize() const { return static_cast(m_data.size()); } - inline Index innerNonZeros(Index j) const { return m_data[j].size(); } - - std::vector >& _data() { return m_data; } - const std::vector >& _data() const { return m_data; } - - /** \returns the coefficient value at given position \a row, \a col - * This operation involes a log(rho*outer_size) binary search. - */ - inline Scalar coeff(Index row, Index col) const - { - const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; - return m_data[outer].at(inner); - } - - /** \returns a reference to the coefficient value at given position \a row, \a col - * This operation involes a log(rho*outer_size) binary search. If the coefficient does not - * exist yet, then a sorted insertion into a sequential buffer is performed. - */ - inline Scalar& coeffRef(Index row, Index col) - { - const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; - return m_data[outer].atWithInsertion(inner); - } - - class InnerIterator; - - void setZero() - { - for (Index j=0; j(m_data[j].size()); - return res; - } - - - - void reserve(Index reserveSize = 1000) - { - if (outerSize()>0) - { - Index reserveSizePerVector = (std::max)(reserveSize/outerSize(),Index(4)); - for (Index j=0; j(m_data[outer].size()) - 1; - m_data[outer].resize(id+2,1); - - while ( (id >= startId) && (m_data[outer].index(id) > inner) ) - { - m_data[outer].index(id+1) = m_data[outer].index(id); - m_data[outer].value(id+1) = m_data[outer].value(id); - --id; - } - m_data[outer].index(id+1) = inner; - m_data[outer].value(id+1) = 0; - return m_data[outer].value(id+1); - } - - /** Does nothing: provided for compatibility with SparseMatrix */ - inline void finalize() {} - - /** Suppress all nonzeros which are smaller than \a reference under the tolerence \a epsilon */ - void prune(Scalar reference, RealScalar epsilon = NumTraits::dummy_precision()) - { - for (Index j=0; jinnerSize) - { - // remove all coefficients with innerCoord>=innerSize - // TODO - //std::cerr << "not implemented yet\n"; - exit(2); - } - if (m_data.size() != outerSize) - { - m_data.resize(outerSize); - } - } - - inline DynamicSparseMatrix() - : m_innerSize(0), m_data(0) - { - eigen_assert(innerSize()==0 && outerSize()==0); - } - - inline DynamicSparseMatrix(Index rows, Index cols) - : m_innerSize(0) - { - resize(rows, cols); - } - - template - explicit inline DynamicSparseMatrix(const SparseMatrixBase& other) - : m_innerSize(0) - { - Base::operator=(other.derived()); - } - - inline DynamicSparseMatrix(const DynamicSparseMatrix& other) - : Base(), m_innerSize(0) - { - *this = other.derived(); - } - - inline void swap(DynamicSparseMatrix& other) - { - //EIGEN_DBG_SPARSE(std::cout << "SparseMatrix:: swap\n"); - std::swap(m_innerSize, other.m_innerSize); - //std::swap(m_outerSize, other.m_outerSize); - m_data.swap(other.m_data); - } - - inline DynamicSparseMatrix& operator=(const DynamicSparseMatrix& other) - { - if (other.isRValue()) - { - swap(other.const_cast_derived()); - } - else - { - resize(other.rows(), other.cols()); - m_data = other.m_data; - } - return *this; - } - - /** Destructor */ - inline ~DynamicSparseMatrix() {} - - public: - - /** \deprecated - * Set the matrix to zero and reserve the memory for \a reserveSize nonzero coefficients. */ - EIGEN_DEPRECATED void startFill(Index reserveSize = 1000) - { - setZero(); - reserve(reserveSize); - } - - /** \deprecated use insert() - * inserts a nonzero coefficient at given coordinates \a row, \a col and returns its reference assuming that: - * 1 - the coefficient does not exist yet - * 2 - this the coefficient with greater inner coordinate for the given outer coordinate. - * In other words, assuming \c *this is column-major, then there must not exists any nonzero coefficient of coordinates - * \c i \c x \a col such that \c i >= \a row. Otherwise the matrix is invalid. - * - * \see fillrand(), coeffRef() - */ - EIGEN_DEPRECATED Scalar& fill(Index row, Index col) - { - const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; - return insertBack(outer,inner); - } - - /** \deprecated use insert() - * Like fill() but with random inner coordinates. - * Compared to the generic coeffRef(), the unique limitation is that we assume - * the coefficient does not exist yet. - */ - EIGEN_DEPRECATED Scalar& fillrand(Index row, Index col) - { - return insert(row,col); - } - - /** \deprecated use finalize() - * Does nothing. Provided for compatibility with SparseMatrix. */ - EIGEN_DEPRECATED void endFill() {} - -# ifdef EIGEN_DYNAMICSPARSEMATRIX_PLUGIN -# include EIGEN_DYNAMICSPARSEMATRIX_PLUGIN -# endif -}; - -template -class DynamicSparseMatrix::InnerIterator : public SparseVector::InnerIterator -{ - typedef typename SparseVector::InnerIterator Base; - public: - InnerIterator(const DynamicSparseMatrix& mat, Index outer) - : Base(mat.m_data[outer]), m_outer(outer) - {} - - inline Index row() const { return IsRowMajor ? m_outer : Base::index(); } - inline Index col() const { return IsRowMajor ? Base::index() : m_outer; } - - protected: - const Index m_outer; -}; - -#endif // EIGEN_DYNAMIC_SPARSEMATRIX_H diff --git a/extern/Eigen3/Eigen/src/Sparse/MappedSparseMatrix.h b/extern/Eigen3/Eigen/src/Sparse/MappedSparseMatrix.h deleted file mode 100644 index 31a431fb224..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/MappedSparseMatrix.h +++ /dev/null @@ -1,165 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_MAPPED_SPARSEMATRIX_H -#define EIGEN_MAPPED_SPARSEMATRIX_H - -/** \class MappedSparseMatrix - * - * \brief Sparse matrix - * - * \param _Scalar the scalar type, i.e. the type of the coefficients - * - * See http://www.netlib.org/linalg/html_templates/node91.html for details on the storage scheme. - * - */ -namespace internal { -template -struct traits > : traits > -{}; -} - -template -class MappedSparseMatrix - : public SparseMatrixBase > -{ - public: - EIGEN_SPARSE_PUBLIC_INTERFACE(MappedSparseMatrix) - - protected: - enum { IsRowMajor = Base::IsRowMajor }; - - Index m_outerSize; - Index m_innerSize; - Index m_nnz; - Index* m_outerIndex; - Index* m_innerIndices; - Scalar* m_values; - - public: - - inline Index rows() const { return IsRowMajor ? m_outerSize : m_innerSize; } - inline Index cols() const { return IsRowMajor ? m_innerSize : m_outerSize; } - inline Index innerSize() const { return m_innerSize; } - inline Index outerSize() const { return m_outerSize; } - inline Index innerNonZeros(Index j) const { return m_outerIndex[j+1]-m_outerIndex[j]; } - - //---------------------------------------- - // direct access interface - inline const Scalar* _valuePtr() const { return m_values; } - inline Scalar* _valuePtr() { return m_values; } - - inline const Index* _innerIndexPtr() const { return m_innerIndices; } - inline Index* _innerIndexPtr() { return m_innerIndices; } - - inline const Index* _outerIndexPtr() const { return m_outerIndex; } - inline Index* _outerIndexPtr() { return m_outerIndex; } - //---------------------------------------- - - inline Scalar coeff(Index row, Index col) const - { - const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; - - Index start = m_outerIndex[outer]; - Index end = m_outerIndex[outer+1]; - if (start==end) - return Scalar(0); - else if (end>0 && inner==m_innerIndices[end-1]) - return m_values[end-1]; - // ^^ optimization: let's first check if it is the last coefficient - // (very common in high level algorithms) - - const Index* r = std::lower_bound(&m_innerIndices[start],&m_innerIndices[end-1],inner); - const Index id = r-&m_innerIndices[0]; - return ((*r==inner) && (id=start && "you probably called coeffRef on a non finalized matrix"); - eigen_assert(end>start && "coeffRef cannot be called on a zero coefficient"); - Index* r = std::lower_bound(&m_innerIndices[start],&m_innerIndices[end],inner); - const Index id = r-&m_innerIndices[0]; - eigen_assert((*r==inner) && (id -class MappedSparseMatrix::InnerIterator -{ - public: - InnerIterator(const MappedSparseMatrix& mat, Index outer) - : m_matrix(mat), - m_outer(outer), - m_id(mat._outerIndexPtr()[outer]), - m_start(m_id), - m_end(mat._outerIndexPtr()[outer+1]) - {} - - template - InnerIterator(const Flagged& mat, Index outer) - : m_matrix(mat._expression()), m_id(m_matrix._outerIndexPtr()[outer]), - m_start(m_id), m_end(m_matrix._outerIndexPtr()[outer+1]) - {} - - inline InnerIterator& operator++() { m_id++; return *this; } - - inline Scalar value() const { return m_matrix._valuePtr()[m_id]; } - inline Scalar& valueRef() { return const_cast(m_matrix._valuePtr()[m_id]); } - - inline Index index() const { return m_matrix._innerIndexPtr()[m_id]; } - inline Index row() const { return IsRowMajor ? m_outer : index(); } - inline Index col() const { return IsRowMajor ? index() : m_outer; } - - inline operator bool() const { return (m_id < m_end) && (m_id>=m_start); } - - protected: - const MappedSparseMatrix& m_matrix; - const Index m_outer; - Index m_id; - const Index m_start; - const Index m_end; -}; - -#endif // EIGEN_MAPPED_SPARSEMATRIX_H diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseAssign.h b/extern/Eigen3/Eigen/src/Sparse/SparseAssign.h deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseBlock.h b/extern/Eigen3/Eigen/src/Sparse/SparseBlock.h deleted file mode 100644 index 8079c999994..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/SparseBlock.h +++ /dev/null @@ -1,465 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSE_BLOCK_H -#define EIGEN_SPARSE_BLOCK_H - -namespace internal { -template -struct traits > -{ - typedef typename traits::Scalar Scalar; - typedef typename traits::Index Index; - typedef typename traits::StorageKind StorageKind; - typedef MatrixXpr XprKind; - enum { - IsRowMajor = (int(MatrixType::Flags)&RowMajorBit)==RowMajorBit, - Flags = MatrixType::Flags, - RowsAtCompileTime = IsRowMajor ? Size : MatrixType::RowsAtCompileTime, - ColsAtCompileTime = IsRowMajor ? MatrixType::ColsAtCompileTime : Size, - MaxRowsAtCompileTime = RowsAtCompileTime, - MaxColsAtCompileTime = ColsAtCompileTime, - CoeffReadCost = MatrixType::CoeffReadCost - }; -}; -} // end namespace internal - -template -class SparseInnerVectorSet : internal::no_assignment_operator, - public SparseMatrixBase > -{ - public: - - enum { IsRowMajor = internal::traits::IsRowMajor }; - - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseInnerVectorSet) - class InnerIterator: public MatrixType::InnerIterator - { - public: - inline InnerIterator(const SparseInnerVectorSet& xpr, Index outer) - : MatrixType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) - {} - inline Index row() const { return IsRowMajor ? m_outer : this->index(); } - inline Index col() const { return IsRowMajor ? this->index() : m_outer; } - protected: - Index m_outer; - }; - - inline SparseInnerVectorSet(const MatrixType& matrix, Index outerStart, Index outerSize) - : m_matrix(matrix), m_outerStart(outerStart), m_outerSize(outerSize) - { - eigen_assert( (outerStart>=0) && ((outerStart+outerSize)<=matrix.outerSize()) ); - } - - inline SparseInnerVectorSet(const MatrixType& matrix, Index outer) - : m_matrix(matrix), m_outerStart(outer), m_outerSize(Size) - { - eigen_assert(Size!=Dynamic); - eigen_assert( (outer>=0) && (outer -// inline SparseInnerVectorSet& operator=(const SparseMatrixBase& other) -// { -// return *this; -// } - -// template -// inline SparseInnerVectorSet& operator=(const SparseMatrixBase& other) -// { -// return *this; -// } - - EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); } - - protected: - - const typename MatrixType::Nested m_matrix; - Index m_outerStart; - const internal::variable_if_dynamic m_outerSize; -}; - -/*************************************************************************** -* specialisation for DynamicSparseMatrix -***************************************************************************/ - -template -class SparseInnerVectorSet, Size> - : public SparseMatrixBase, Size> > -{ - typedef DynamicSparseMatrix<_Scalar, _Options> MatrixType; - public: - - enum { IsRowMajor = internal::traits::IsRowMajor }; - - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseInnerVectorSet) - class InnerIterator: public MatrixType::InnerIterator - { - public: - inline InnerIterator(const SparseInnerVectorSet& xpr, Index outer) - : MatrixType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) - {} - inline Index row() const { return IsRowMajor ? m_outer : this->index(); } - inline Index col() const { return IsRowMajor ? this->index() : m_outer; } - protected: - Index m_outer; - }; - - inline SparseInnerVectorSet(const MatrixType& matrix, Index outerStart, Index outerSize) - : m_matrix(matrix), m_outerStart(outerStart), m_outerSize(outerSize) - { - eigen_assert( (outerStart>=0) && ((outerStart+outerSize)<=matrix.outerSize()) ); - } - - inline SparseInnerVectorSet(const MatrixType& matrix, Index outer) - : m_matrix(matrix), m_outerStart(outer), m_outerSize(Size) - { - eigen_assert(Size!=Dynamic); - eigen_assert( (outer>=0) && (outer - inline SparseInnerVectorSet& operator=(const SparseMatrixBase& other) - { - if (IsRowMajor != ((OtherDerived::Flags&RowMajorBit)==RowMajorBit)) - { - // need to transpose => perform a block evaluation followed by a big swap - DynamicSparseMatrix aux(other); - *this = aux.markAsRValue(); - } - else - { - // evaluate/copy vector per vector - for (Index j=0; j aux(other.innerVector(j)); - m_matrix.const_cast_derived()._data()[m_outerStart+j].swap(aux._data()); - } - } - return *this; - } - - inline SparseInnerVectorSet& operator=(const SparseInnerVectorSet& other) - { - return operator=(other); - } - - Index nonZeros() const - { - Index count = 0; - for (Index j=0; j0); - return m_matrix.data()[m_outerStart].vale(m_matrix.data()[m_outerStart].size()-1); - } - -// template -// inline SparseInnerVectorSet& operator=(const SparseMatrixBase& other) -// { -// return *this; -// } - - EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); } - - protected: - - const typename MatrixType::Nested m_matrix; - Index m_outerStart; - const internal::variable_if_dynamic m_outerSize; - -}; - - -/*************************************************************************** -* specialisation for SparseMatrix -***************************************************************************/ - -template -class SparseInnerVectorSet, Size> - : public SparseMatrixBase, Size> > -{ - typedef SparseMatrix<_Scalar, _Options> MatrixType; - public: - - enum { IsRowMajor = internal::traits::IsRowMajor }; - - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseInnerVectorSet) - class InnerIterator: public MatrixType::InnerIterator - { - public: - inline InnerIterator(const SparseInnerVectorSet& xpr, Index outer) - : MatrixType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) - {} - inline Index row() const { return IsRowMajor ? m_outer : this->index(); } - inline Index col() const { return IsRowMajor ? this->index() : m_outer; } - protected: - Index m_outer; - }; - - inline SparseInnerVectorSet(const MatrixType& matrix, Index outerStart, Index outerSize) - : m_matrix(matrix), m_outerStart(outerStart), m_outerSize(outerSize) - { - eigen_assert( (outerStart>=0) && ((outerStart+outerSize)<=matrix.outerSize()) ); - } - - inline SparseInnerVectorSet(const MatrixType& matrix, Index outer) - : m_matrix(matrix), m_outerStart(outer), m_outerSize(Size) - { - eigen_assert(Size==1); - eigen_assert( (outer>=0) && (outer - inline SparseInnerVectorSet& operator=(const SparseMatrixBase& other) - { - typedef typename internal::remove_all::type _NestedMatrixType; - _NestedMatrixType& matrix = const_cast<_NestedMatrixType&>(m_matrix);; - // This assignement is slow if this vector set not empty - // and/or it is not at the end of the nonzeros of the underlying matrix. - - // 1 - eval to a temporary to avoid transposition and/or aliasing issues - SparseMatrix tmp(other); - - // 2 - let's check whether there is enough allocated memory - Index nnz = tmp.nonZeros(); - Index nnz_previous = nonZeros(); - Index free_size = matrix.data().allocatedSize() - nnz_previous; - std::size_t nnz_head = m_outerStart==0 ? 0 : matrix._outerIndexPtr()[m_outerStart]; - std::size_t tail = m_matrix._outerIndexPtr()[m_outerStart+m_outerSize.value()]; - std::size_t nnz_tail = matrix.nonZeros() - tail; - - if(nnz>free_size) - { - // realloc manually to reduce copies - typename MatrixType::Storage newdata(m_matrix.nonZeros() - nnz_previous + nnz); - - std::memcpy(&newdata.value(0), &m_matrix.data().value(0), nnz_head*sizeof(Scalar)); - std::memcpy(&newdata.index(0), &m_matrix.data().index(0), nnz_head*sizeof(Index)); - - std::memcpy(&newdata.value(nnz_head), &tmp.data().value(0), nnz*sizeof(Scalar)); - std::memcpy(&newdata.index(nnz_head), &tmp.data().index(0), nnz*sizeof(Index)); - - std::memcpy(&newdata.value(nnz_head+nnz), &matrix.data().value(tail), nnz_tail*sizeof(Scalar)); - std::memcpy(&newdata.index(nnz_head+nnz), &matrix.data().index(tail), nnz_tail*sizeof(Index)); - - matrix.data().swap(newdata); - } - else - { - // no need to realloc, simply copy the tail at its respective position and insert tmp - matrix.data().resize(nnz_head + nnz + nnz_tail); - - if(nnz=0; --i) - { - matrix.data().value(nnz_head+nnz+i) = matrix.data().value(tail+i); - matrix.data().index(nnz_head+nnz+i) = matrix.data().index(tail+i); - } - } - - std::memcpy(&matrix.data().value(nnz_head), &tmp.data().value(0), nnz*sizeof(Scalar)); - std::memcpy(&matrix.data().index(nnz_head), &tmp.data().index(0), nnz*sizeof(Index)); - } - - // update outer index pointers - Index p = nnz_head; - for(Index k=1; k(other); - } - - inline const Scalar* _valuePtr() const - { return m_matrix._valuePtr() + m_matrix._outerIndexPtr()[m_outerStart]; } - inline Scalar* _valuePtr() - { return m_matrix.const_cast_derived()._valuePtr() + m_matrix._outerIndexPtr()[m_outerStart]; } - - inline const Index* _innerIndexPtr() const - { return m_matrix._innerIndexPtr() + m_matrix._outerIndexPtr()[m_outerStart]; } - inline Index* _innerIndexPtr() - { return m_matrix.const_cast_derived()._innerIndexPtr() + m_matrix._outerIndexPtr()[m_outerStart]; } - - inline const Index* _outerIndexPtr() const - { return m_matrix._outerIndexPtr() + m_outerStart; } - inline Index* _outerIndexPtr() - { return m_matrix.const_cast_derived()._outerIndexPtr() + m_outerStart; } - - Index nonZeros() const - { - return std::size_t(m_matrix._outerIndexPtr()[m_outerStart+m_outerSize.value()]) - - std::size_t(m_matrix._outerIndexPtr()[m_outerStart]); - } - - const Scalar& lastCoeff() const - { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(SparseInnerVectorSet); - eigen_assert(nonZeros()>0); - return m_matrix._valuePtr()[m_matrix._outerIndexPtr()[m_outerStart+1]-1]; - } - -// template -// inline SparseInnerVectorSet& operator=(const SparseMatrixBase& other) -// { -// return *this; -// } - - EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); } - - protected: - - const typename MatrixType::Nested m_matrix; - Index m_outerStart; - const internal::variable_if_dynamic m_outerSize; - -}; - -//---------- - -/** \returns the i-th row of the matrix \c *this. For row-major matrix only. */ -template -SparseInnerVectorSet SparseMatrixBase::row(Index i) -{ - EIGEN_STATIC_ASSERT(IsRowMajor,THIS_METHOD_IS_ONLY_FOR_ROW_MAJOR_MATRICES); - return innerVector(i); -} - -/** \returns the i-th row of the matrix \c *this. For row-major matrix only. - * (read-only version) */ -template -const SparseInnerVectorSet SparseMatrixBase::row(Index i) const -{ - EIGEN_STATIC_ASSERT(IsRowMajor,THIS_METHOD_IS_ONLY_FOR_ROW_MAJOR_MATRICES); - return innerVector(i); -} - -/** \returns the i-th column of the matrix \c *this. For column-major matrix only. */ -template -SparseInnerVectorSet SparseMatrixBase::col(Index i) -{ - EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); - return innerVector(i); -} - -/** \returns the i-th column of the matrix \c *this. For column-major matrix only. - * (read-only version) */ -template -const SparseInnerVectorSet SparseMatrixBase::col(Index i) const -{ - EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); - return innerVector(i); -} - -/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this - * is col-major (resp. row-major). - */ -template -SparseInnerVectorSet SparseMatrixBase::innerVector(Index outer) -{ return SparseInnerVectorSet(derived(), outer); } - -/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this - * is col-major (resp. row-major). Read-only. - */ -template -const SparseInnerVectorSet SparseMatrixBase::innerVector(Index outer) const -{ return SparseInnerVectorSet(derived(), outer); } - -//---------- - -/** \returns the i-th row of the matrix \c *this. For row-major matrix only. */ -template -SparseInnerVectorSet SparseMatrixBase::subrows(Index start, Index size) -{ - EIGEN_STATIC_ASSERT(IsRowMajor,THIS_METHOD_IS_ONLY_FOR_ROW_MAJOR_MATRICES); - return innerVectors(start, size); -} - -/** \returns the i-th row of the matrix \c *this. For row-major matrix only. - * (read-only version) */ -template -const SparseInnerVectorSet SparseMatrixBase::subrows(Index start, Index size) const -{ - EIGEN_STATIC_ASSERT(IsRowMajor,THIS_METHOD_IS_ONLY_FOR_ROW_MAJOR_MATRICES); - return innerVectors(start, size); -} - -/** \returns the i-th column of the matrix \c *this. For column-major matrix only. */ -template -SparseInnerVectorSet SparseMatrixBase::subcols(Index start, Index size) -{ - EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); - return innerVectors(start, size); -} - -/** \returns the i-th column of the matrix \c *this. For column-major matrix only. - * (read-only version) */ -template -const SparseInnerVectorSet SparseMatrixBase::subcols(Index start, Index size) const -{ - EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); - return innerVectors(start, size); -} - -/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this - * is col-major (resp. row-major). - */ -template -SparseInnerVectorSet SparseMatrixBase::innerVectors(Index outerStart, Index outerSize) -{ return SparseInnerVectorSet(derived(), outerStart, outerSize); } - -/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this - * is col-major (resp. row-major). Read-only. - */ -template -const SparseInnerVectorSet SparseMatrixBase::innerVectors(Index outerStart, Index outerSize) const -{ return SparseInnerVectorSet(derived(), outerStart, outerSize); } - -#endif // EIGEN_SPARSE_BLOCK_H diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseCwiseBinaryOp.h b/extern/Eigen3/Eigen/src/Sparse/SparseCwiseBinaryOp.h deleted file mode 100644 index cde5bbc0300..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/SparseCwiseBinaryOp.h +++ /dev/null @@ -1,375 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSE_CWISE_BINARY_OP_H -#define EIGEN_SPARSE_CWISE_BINARY_OP_H - -// Here we have to handle 3 cases: -// 1 - sparse op dense -// 2 - dense op sparse -// 3 - sparse op sparse -// We also need to implement a 4th iterator for: -// 4 - dense op dense -// Finally, we also need to distinguish between the product and other operations : -// configuration returned mode -// 1 - sparse op dense product sparse -// generic dense -// 2 - dense op sparse product sparse -// generic dense -// 3 - sparse op sparse product sparse -// generic sparse -// 4 - dense op dense product dense -// generic dense - -namespace internal { - -template<> struct promote_storage_type -{ typedef Sparse ret; }; - -template<> struct promote_storage_type -{ typedef Sparse ret; }; - -template::StorageKind, - typename _RhsStorageMode = typename traits::StorageKind> -class sparse_cwise_binary_op_inner_iterator_selector; - -} // end namespace internal - -template -class CwiseBinaryOpImpl - : public SparseMatrixBase > -{ - public: - class InnerIterator; - typedef CwiseBinaryOp Derived; - EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) -}; - -template -class CwiseBinaryOpImpl::InnerIterator - : public internal::sparse_cwise_binary_op_inner_iterator_selector::InnerIterator> -{ - public: - typedef typename Lhs::Index Index; - typedef internal::sparse_cwise_binary_op_inner_iterator_selector< - BinaryOp,Lhs,Rhs, InnerIterator> Base; - - EIGEN_STRONG_INLINE InnerIterator(const CwiseBinaryOpImpl& binOp, Index outer) - : Base(binOp.derived(),outer) - {} -}; - -/*************************************************************************** -* Implementation of inner-iterators -***************************************************************************/ - -// template struct internal::func_is_conjunction { enum { ret = false }; }; -// template struct internal::func_is_conjunction > { enum { ret = true }; }; - -// TODO generalize the internal::scalar_product_op specialization to all conjunctions if any ! - -namespace internal { - -// sparse - sparse (generic) -template -class sparse_cwise_binary_op_inner_iterator_selector -{ - typedef CwiseBinaryOp CwiseBinaryXpr; - typedef typename traits::Scalar Scalar; - typedef typename traits::_LhsNested _LhsNested; - typedef typename traits::_RhsNested _RhsNested; - typedef typename _LhsNested::InnerIterator LhsIterator; - typedef typename _RhsNested::InnerIterator RhsIterator; - typedef typename Lhs::Index Index; - - public: - - EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) - : m_lhsIter(xpr.lhs(),outer), m_rhsIter(xpr.rhs(),outer), m_functor(xpr.functor()) - { - this->operator++(); - } - - EIGEN_STRONG_INLINE Derived& operator++() - { - if (m_lhsIter && m_rhsIter && (m_lhsIter.index() == m_rhsIter.index())) - { - m_id = m_lhsIter.index(); - m_value = m_functor(m_lhsIter.value(), m_rhsIter.value()); - ++m_lhsIter; - ++m_rhsIter; - } - else if (m_lhsIter && (!m_rhsIter || (m_lhsIter.index() < m_rhsIter.index()))) - { - m_id = m_lhsIter.index(); - m_value = m_functor(m_lhsIter.value(), Scalar(0)); - ++m_lhsIter; - } - else if (m_rhsIter && (!m_lhsIter || (m_lhsIter.index() > m_rhsIter.index()))) - { - m_id = m_rhsIter.index(); - m_value = m_functor(Scalar(0), m_rhsIter.value()); - ++m_rhsIter; - } - else - { - m_value = 0; // this is to avoid a compilation warning - m_id = -1; - } - return *static_cast(this); - } - - EIGEN_STRONG_INLINE Scalar value() const { return m_value; } - - EIGEN_STRONG_INLINE Index index() const { return m_id; } - EIGEN_STRONG_INLINE Index row() const { return Lhs::IsRowMajor ? m_lhsIter.row() : index(); } - EIGEN_STRONG_INLINE Index col() const { return Lhs::IsRowMajor ? index() : m_lhsIter.col(); } - - EIGEN_STRONG_INLINE operator bool() const { return m_id>=0; } - - protected: - LhsIterator m_lhsIter; - RhsIterator m_rhsIter; - const BinaryOp& m_functor; - Scalar m_value; - Index m_id; -}; - -// sparse - sparse (product) -template -class sparse_cwise_binary_op_inner_iterator_selector, Lhs, Rhs, Derived, Sparse, Sparse> -{ - typedef scalar_product_op BinaryFunc; - typedef CwiseBinaryOp CwiseBinaryXpr; - typedef typename CwiseBinaryXpr::Scalar Scalar; - typedef typename traits::_LhsNested _LhsNested; - typedef typename _LhsNested::InnerIterator LhsIterator; - typedef typename traits::_RhsNested _RhsNested; - typedef typename _RhsNested::InnerIterator RhsIterator; - typedef typename Lhs::Index Index; - public: - - EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) - : m_lhsIter(xpr.lhs(),outer), m_rhsIter(xpr.rhs(),outer), m_functor(xpr.functor()) - { - while (m_lhsIter && m_rhsIter && (m_lhsIter.index() != m_rhsIter.index())) - { - if (m_lhsIter.index() < m_rhsIter.index()) - ++m_lhsIter; - else - ++m_rhsIter; - } - } - - EIGEN_STRONG_INLINE Derived& operator++() - { - ++m_lhsIter; - ++m_rhsIter; - while (m_lhsIter && m_rhsIter && (m_lhsIter.index() != m_rhsIter.index())) - { - if (m_lhsIter.index() < m_rhsIter.index()) - ++m_lhsIter; - else - ++m_rhsIter; - } - return *static_cast(this); - } - - EIGEN_STRONG_INLINE Scalar value() const { return m_functor(m_lhsIter.value(), m_rhsIter.value()); } - - EIGEN_STRONG_INLINE Index index() const { return m_lhsIter.index(); } - EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); } - EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); } - - EIGEN_STRONG_INLINE operator bool() const { return (m_lhsIter && m_rhsIter); } - - protected: - LhsIterator m_lhsIter; - RhsIterator m_rhsIter; - const BinaryFunc& m_functor; -}; - -// sparse - dense (product) -template -class sparse_cwise_binary_op_inner_iterator_selector, Lhs, Rhs, Derived, Sparse, Dense> -{ - typedef scalar_product_op BinaryFunc; - typedef CwiseBinaryOp CwiseBinaryXpr; - typedef typename CwiseBinaryXpr::Scalar Scalar; - typedef typename traits::_LhsNested _LhsNested; - typedef typename traits::RhsNested RhsNested; - typedef typename _LhsNested::InnerIterator LhsIterator; - typedef typename Lhs::Index Index; - enum { IsRowMajor = (int(Lhs::Flags)&RowMajorBit)==RowMajorBit }; - public: - - EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) - : m_rhs(xpr.rhs()), m_lhsIter(xpr.lhs(),outer), m_functor(xpr.functor()), m_outer(outer) - {} - - EIGEN_STRONG_INLINE Derived& operator++() - { - ++m_lhsIter; - return *static_cast(this); - } - - EIGEN_STRONG_INLINE Scalar value() const - { return m_functor(m_lhsIter.value(), - m_rhs.coeff(IsRowMajor?m_outer:m_lhsIter.index(),IsRowMajor?m_lhsIter.index():m_outer)); } - - EIGEN_STRONG_INLINE Index index() const { return m_lhsIter.index(); } - EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); } - EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); } - - EIGEN_STRONG_INLINE operator bool() const { return m_lhsIter; } - - protected: - const RhsNested m_rhs; - LhsIterator m_lhsIter; - const BinaryFunc m_functor; - const Index m_outer; -}; - -// sparse - dense (product) -template -class sparse_cwise_binary_op_inner_iterator_selector, Lhs, Rhs, Derived, Dense, Sparse> -{ - typedef scalar_product_op BinaryFunc; - typedef CwiseBinaryOp CwiseBinaryXpr; - typedef typename CwiseBinaryXpr::Scalar Scalar; - typedef typename traits::_RhsNested _RhsNested; - typedef typename _RhsNested::InnerIterator RhsIterator; - typedef typename Lhs::Index Index; - - enum { IsRowMajor = (int(Rhs::Flags)&RowMajorBit)==RowMajorBit }; - public: - - EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) - : m_xpr(xpr), m_rhsIter(xpr.rhs(),outer), m_functor(xpr.functor()), m_outer(outer) - {} - - EIGEN_STRONG_INLINE Derived& operator++() - { - ++m_rhsIter; - return *static_cast(this); - } - - EIGEN_STRONG_INLINE Scalar value() const - { return m_functor(m_xpr.lhs().coeff(IsRowMajor?m_outer:m_rhsIter.index(),IsRowMajor?m_rhsIter.index():m_outer), m_rhsIter.value()); } - - EIGEN_STRONG_INLINE Index index() const { return m_rhsIter.index(); } - EIGEN_STRONG_INLINE Index row() const { return m_rhsIter.row(); } - EIGEN_STRONG_INLINE Index col() const { return m_rhsIter.col(); } - - EIGEN_STRONG_INLINE operator bool() const { return m_rhsIter; } - - protected: - const CwiseBinaryXpr& m_xpr; - RhsIterator m_rhsIter; - const BinaryFunc& m_functor; - const Index m_outer; -}; - -} // end namespace internal - -/*************************************************************************** -* Implementation of SparseMatrixBase and SparseCwise functions/operators -***************************************************************************/ - -// template -// template -// EIGEN_STRONG_INLINE const CwiseBinaryOp::Scalar>, -// Derived, OtherDerived> -// SparseMatrixBase::operator-(const SparseMatrixBase &other) const -// { -// return CwiseBinaryOp, -// Derived, OtherDerived>(derived(), other.derived()); -// } - -template -template -EIGEN_STRONG_INLINE Derived & -SparseMatrixBase::operator-=(const SparseMatrixBase &other) -{ - return *this = derived() - other.derived(); -} - -// template -// template -// EIGEN_STRONG_INLINE const CwiseBinaryOp::Scalar>, Derived, OtherDerived> -// SparseMatrixBase::operator+(const SparseMatrixBase &other) const -// { -// return CwiseBinaryOp, Derived, OtherDerived>(derived(), other.derived()); -// } - -template -template -EIGEN_STRONG_INLINE Derived & -SparseMatrixBase::operator+=(const SparseMatrixBase& other) -{ - return *this = derived() + other.derived(); -} - -// template -// template -// EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE -// SparseCwise::operator*(const SparseMatrixBase &other) const -// { -// return EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE(_expression(), other.derived()); -// } - -template -template -EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE -SparseMatrixBase::cwiseProduct(const MatrixBase &other) const -{ - return EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE(derived(), other.derived()); -} - -// template -// template -// EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_BINOP_RETURN_TYPE(internal::scalar_quotient_op) -// SparseCwise::operator/(const SparseMatrixBase &other) const -// { -// return EIGEN_SPARSE_CWISE_BINOP_RETURN_TYPE(internal::scalar_quotient_op)(_expression(), other.derived()); -// } -// -// template -// template -// EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_BINOP_RETURN_TYPE(internal::scalar_quotient_op) -// SparseCwise::operator/(const MatrixBase &other) const -// { -// return EIGEN_SPARSE_CWISE_BINOP_RETURN_TYPE(internal::scalar_quotient_op)(_expression(), other.derived()); -// } - -// template -// template -// inline ExpressionType& SparseCwise::operator*=(const SparseMatrixBase &other) -// { -// return m_matrix.const_cast_derived() = _expression() * other.derived(); -// } - - -#endif // EIGEN_SPARSE_CWISE_BINARY_OP_H diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseCwiseUnaryOp.h b/extern/Eigen3/Eigen/src/Sparse/SparseCwiseUnaryOp.h deleted file mode 100644 index aa068835fbb..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/SparseCwiseUnaryOp.h +++ /dev/null @@ -1,146 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2010 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSE_CWISE_UNARY_OP_H -#define EIGEN_SPARSE_CWISE_UNARY_OP_H - -// template -// struct internal::traits > : internal::traits -// { -// typedef typename internal::result_of< -// UnaryOp(typename MatrixType::Scalar) -// >::type Scalar; -// typedef typename MatrixType::Nested MatrixTypeNested; -// typedef typename internal::remove_reference::type _MatrixTypeNested; -// enum { -// CoeffReadCost = _MatrixTypeNested::CoeffReadCost + internal::functor_traits::Cost -// }; -// }; - -template -class CwiseUnaryOpImpl - : public SparseMatrixBase > -{ - public: - - class InnerIterator; -// typedef typename internal::remove_reference::type _LhsNested; - - typedef CwiseUnaryOp Derived; - EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) -}; - -template -class CwiseUnaryOpImpl::InnerIterator -{ - typedef typename CwiseUnaryOpImpl::Scalar Scalar; - typedef typename internal::traits::_XprTypeNested _MatrixTypeNested; - typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator; - typedef typename MatrixType::Index Index; - public: - - EIGEN_STRONG_INLINE InnerIterator(const CwiseUnaryOpImpl& unaryOp, Index outer) - : m_iter(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) - {} - - EIGEN_STRONG_INLINE InnerIterator& operator++() - { ++m_iter; return *this; } - - EIGEN_STRONG_INLINE Scalar value() const { return m_functor(m_iter.value()); } - - EIGEN_STRONG_INLINE Index index() const { return m_iter.index(); } - EIGEN_STRONG_INLINE Index row() const { return m_iter.row(); } - EIGEN_STRONG_INLINE Index col() const { return m_iter.col(); } - - EIGEN_STRONG_INLINE operator bool() const { return m_iter; } - - protected: - MatrixTypeIterator m_iter; - const UnaryOp m_functor; -}; - -template -class CwiseUnaryViewImpl - : public SparseMatrixBase > -{ - public: - - class InnerIterator; -// typedef typename internal::remove_reference::type _LhsNested; - - typedef CwiseUnaryView Derived; - EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) -}; - -template -class CwiseUnaryViewImpl::InnerIterator -{ - typedef typename CwiseUnaryViewImpl::Scalar Scalar; - typedef typename internal::traits::_MatrixTypeNested _MatrixTypeNested; - typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator; - typedef typename MatrixType::Index Index; - public: - - EIGEN_STRONG_INLINE InnerIterator(const CwiseUnaryViewImpl& unaryView, Index outer) - : m_iter(unaryView.derived().nestedExpression(),outer), m_functor(unaryView.derived().functor()) - {} - - EIGEN_STRONG_INLINE InnerIterator& operator++() - { ++m_iter; return *this; } - - EIGEN_STRONG_INLINE Scalar value() const { return m_functor(m_iter.value()); } - EIGEN_STRONG_INLINE Scalar& valueRef() { return m_functor(m_iter.valueRef()); } - - EIGEN_STRONG_INLINE Index index() const { return m_iter.index(); } - EIGEN_STRONG_INLINE Index row() const { return m_iter.row(); } - EIGEN_STRONG_INLINE Index col() const { return m_iter.col(); } - - EIGEN_STRONG_INLINE operator bool() const { return m_iter; } - - protected: - MatrixTypeIterator m_iter; - const ViewOp m_functor; -}; - -template -EIGEN_STRONG_INLINE Derived& -SparseMatrixBase::operator*=(const Scalar& other) -{ - for (Index j=0; j -EIGEN_STRONG_INLINE Derived& -SparseMatrixBase::operator/=(const Scalar& other) -{ - for (Index j=0; j -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSEDENSEPRODUCT_H -#define EIGEN_SPARSEDENSEPRODUCT_H - -template struct SparseDenseProductReturnType -{ - typedef SparseTimeDenseProduct Type; -}; - -template struct SparseDenseProductReturnType -{ - typedef SparseDenseOuterProduct Type; -}; - -template struct DenseSparseProductReturnType -{ - typedef DenseTimeSparseProduct Type; -}; - -template struct DenseSparseProductReturnType -{ - typedef SparseDenseOuterProduct Type; -}; - -namespace internal { - -template -struct traits > -{ - typedef Sparse StorageKind; - typedef typename scalar_product_traits::Scalar, - typename traits::Scalar>::ReturnType Scalar; - typedef typename Lhs::Index Index; - typedef typename Lhs::Nested LhsNested; - typedef typename Rhs::Nested RhsNested; - typedef typename remove_all::type _LhsNested; - typedef typename remove_all::type _RhsNested; - - enum { - LhsCoeffReadCost = traits<_LhsNested>::CoeffReadCost, - RhsCoeffReadCost = traits<_RhsNested>::CoeffReadCost, - - RowsAtCompileTime = Tr ? int(traits::RowsAtCompileTime) : int(traits::RowsAtCompileTime), - ColsAtCompileTime = Tr ? int(traits::ColsAtCompileTime) : int(traits::ColsAtCompileTime), - MaxRowsAtCompileTime = Tr ? int(traits::MaxRowsAtCompileTime) : int(traits::MaxRowsAtCompileTime), - MaxColsAtCompileTime = Tr ? int(traits::MaxColsAtCompileTime) : int(traits::MaxColsAtCompileTime), - - Flags = Tr ? RowMajorBit : 0, - - CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + NumTraits::MulCost - }; -}; - -} // end namespace internal - -template -class SparseDenseOuterProduct - : public SparseMatrixBase > -{ - public: - - typedef SparseMatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(SparseDenseOuterProduct) - typedef internal::traits Traits; - - private: - - typedef typename Traits::LhsNested LhsNested; - typedef typename Traits::RhsNested RhsNested; - typedef typename Traits::_LhsNested _LhsNested; - typedef typename Traits::_RhsNested _RhsNested; - - public: - - class InnerIterator; - - EIGEN_STRONG_INLINE SparseDenseOuterProduct(const Lhs& lhs, const Rhs& rhs) - : m_lhs(lhs), m_rhs(rhs) - { - EIGEN_STATIC_ASSERT(!Tr,YOU_MADE_A_PROGRAMMING_MISTAKE); - } - - EIGEN_STRONG_INLINE SparseDenseOuterProduct(const Rhs& rhs, const Lhs& lhs) - : m_lhs(lhs), m_rhs(rhs) - { - EIGEN_STATIC_ASSERT(Tr,YOU_MADE_A_PROGRAMMING_MISTAKE); - } - - EIGEN_STRONG_INLINE Index rows() const { return Tr ? m_rhs.rows() : m_lhs.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return Tr ? m_lhs.cols() : m_rhs.cols(); } - - EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; } - EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; } - - protected: - LhsNested m_lhs; - RhsNested m_rhs; -}; - -template -class SparseDenseOuterProduct::InnerIterator : public _LhsNested::InnerIterator -{ - typedef typename _LhsNested::InnerIterator Base; - public: - EIGEN_STRONG_INLINE InnerIterator(const SparseDenseOuterProduct& prod, Index outer) - : Base(prod.lhs(), 0), m_outer(outer), m_factor(prod.rhs().coeff(outer)) - { - } - - inline Index outer() const { return m_outer; } - inline Index row() const { return Transpose ? Base::row() : m_outer; } - inline Index col() const { return Transpose ? m_outer : Base::row(); } - - inline Scalar value() const { return Base::value() * m_factor; } - - protected: - int m_outer; - Scalar m_factor; -}; - -namespace internal { -template -struct traits > - : traits, Lhs, Rhs> > -{ - typedef Dense StorageKind; - typedef MatrixXpr XprKind; -}; -} // end namespace internal - -template -class SparseTimeDenseProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(SparseTimeDenseProduct) - - SparseTimeDenseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - {} - - template void scaleAndAddTo(Dest& dest, Scalar alpha) const - { - typedef typename internal::remove_all::type _Lhs; - typedef typename internal::remove_all::type _Rhs; - typedef typename _Lhs::InnerIterator LhsInnerIterator; - enum { LhsIsRowMajor = (_Lhs::Flags&RowMajorBit)==RowMajorBit }; - for(Index j=0; j -struct traits > - : traits, Lhs, Rhs> > -{ - typedef Dense StorageKind; -}; -} // end namespace internal - -template -class DenseTimeSparseProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(DenseTimeSparseProduct) - - DenseTimeSparseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - {} - - template void scaleAndAddTo(Dest& dest, Scalar alpha) const - { - typedef typename internal::remove_all::type _Rhs; - typedef typename _Rhs::InnerIterator RhsInnerIterator; - enum { RhsIsRowMajor = (_Rhs::Flags&RowMajorBit)==RowMajorBit }; - for(Index j=0; j -template -inline const typename SparseDenseProductReturnType::Type -SparseMatrixBase::operator*(const MatrixBase &other) const -{ - return typename SparseDenseProductReturnType::Type(derived(), other.derived()); -} - -#endif // EIGEN_SPARSEDENSEPRODUCT_H diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseDiagonalProduct.h b/extern/Eigen3/Eigen/src/Sparse/SparseDiagonalProduct.h deleted file mode 100644 index fb9a29c051b..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/SparseDiagonalProduct.h +++ /dev/null @@ -1,195 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSE_DIAGONAL_PRODUCT_H -#define EIGEN_SPARSE_DIAGONAL_PRODUCT_H - -// The product of a diagonal matrix with a sparse matrix can be easily -// implemented using expression template. -// We have two consider very different cases: -// 1 - diag * row-major sparse -// => each inner vector <=> scalar * sparse vector product -// => so we can reuse CwiseUnaryOp::InnerIterator -// 2 - diag * col-major sparse -// => each inner vector <=> densevector * sparse vector cwise product -// => again, we can reuse specialization of CwiseBinaryOp::InnerIterator -// for that particular case -// The two other cases are symmetric. - -namespace internal { - -template -struct traits > -{ - typedef typename remove_all::type _Lhs; - typedef typename remove_all::type _Rhs; - typedef typename _Lhs::Scalar Scalar; - typedef typename promote_index_type::Index, - typename traits::Index>::type Index; - typedef Sparse StorageKind; - typedef MatrixXpr XprKind; - enum { - RowsAtCompileTime = _Lhs::RowsAtCompileTime, - ColsAtCompileTime = _Rhs::ColsAtCompileTime, - - MaxRowsAtCompileTime = _Lhs::MaxRowsAtCompileTime, - MaxColsAtCompileTime = _Rhs::MaxColsAtCompileTime, - - SparseFlags = is_diagonal<_Lhs>::ret ? int(_Rhs::Flags) : int(_Lhs::Flags), - Flags = (SparseFlags&RowMajorBit), - CoeffReadCost = Dynamic - }; -}; - -enum {SDP_IsDiagonal, SDP_IsSparseRowMajor, SDP_IsSparseColMajor}; -template -class sparse_diagonal_product_inner_iterator_selector; - -} // end namespace internal - -template -class SparseDiagonalProduct - : public SparseMatrixBase >, - internal::no_assignment_operator -{ - typedef typename Lhs::Nested LhsNested; - typedef typename Rhs::Nested RhsNested; - - typedef typename internal::remove_all::type _LhsNested; - typedef typename internal::remove_all::type _RhsNested; - - enum { - LhsMode = internal::is_diagonal<_LhsNested>::ret ? internal::SDP_IsDiagonal - : (_LhsNested::Flags&RowMajorBit) ? internal::SDP_IsSparseRowMajor : internal::SDP_IsSparseColMajor, - RhsMode = internal::is_diagonal<_RhsNested>::ret ? internal::SDP_IsDiagonal - : (_RhsNested::Flags&RowMajorBit) ? internal::SDP_IsSparseRowMajor : internal::SDP_IsSparseColMajor - }; - - public: - - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseDiagonalProduct) - - typedef internal::sparse_diagonal_product_inner_iterator_selector - <_LhsNested,_RhsNested,SparseDiagonalProduct,LhsMode,RhsMode> InnerIterator; - - EIGEN_STRONG_INLINE SparseDiagonalProduct(const Lhs& lhs, const Rhs& rhs) - : m_lhs(lhs), m_rhs(rhs) - { - eigen_assert(lhs.cols() == rhs.rows() && "invalid sparse matrix * diagonal matrix product"); - } - - EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); } - - EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; } - EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; } - - protected: - LhsNested m_lhs; - RhsNested m_rhs; -}; - -namespace internal { - -template -class sparse_diagonal_product_inner_iterator_selector - - : public CwiseUnaryOp,const Rhs>::InnerIterator -{ - typedef typename CwiseUnaryOp,const Rhs>::InnerIterator Base; - typedef typename Lhs::Index Index; - public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.rhs()*(expr.lhs().diagonal().coeff(outer)), outer) - {} -}; - -template -class sparse_diagonal_product_inner_iterator_selector - - : public CwiseBinaryOp< - scalar_product_op, - SparseInnerVectorSet, - typename Lhs::DiagonalVectorType>::InnerIterator -{ - typedef typename CwiseBinaryOp< - scalar_product_op, - SparseInnerVectorSet, - typename Lhs::DiagonalVectorType>::InnerIterator Base; - typedef typename Lhs::Index Index; - public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.rhs().innerVector(outer) .cwiseProduct(expr.lhs().diagonal()), 0) - {} -}; - -template -class sparse_diagonal_product_inner_iterator_selector - - : public CwiseUnaryOp,const Lhs>::InnerIterator -{ - typedef typename CwiseUnaryOp,const Lhs>::InnerIterator Base; - typedef typename Lhs::Index Index; - public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.lhs()*expr.rhs().diagonal().coeff(outer), outer) - {} -}; - -template -class sparse_diagonal_product_inner_iterator_selector - - : public CwiseBinaryOp< - scalar_product_op, - SparseInnerVectorSet, - Transpose >::InnerIterator -{ - typedef typename CwiseBinaryOp< - scalar_product_op, - SparseInnerVectorSet, - Transpose >::InnerIterator Base; - typedef typename Lhs::Index Index; - public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.lhs().innerVector(outer) .cwiseProduct(expr.rhs().diagonal().transpose()), 0) - {} -}; - -} // end namespace internal - -// SparseMatrixBase functions - -template -template -const SparseDiagonalProduct -SparseMatrixBase::operator*(const DiagonalBase &other) const -{ - return SparseDiagonalProduct(this->derived(), other.derived()); -} - -#endif // EIGEN_SPARSE_DIAGONAL_PRODUCT_H diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseDot.h b/extern/Eigen3/Eigen/src/Sparse/SparseDot.h deleted file mode 100644 index 1f10f71a402..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/SparseDot.h +++ /dev/null @@ -1,97 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSE_DOT_H -#define EIGEN_SPARSE_DOT_H - -template -template -typename internal::traits::Scalar -SparseMatrixBase::dot(const MatrixBase& other) const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) - EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - eigen_assert(size() == other.size()); - eigen_assert(other.size()>0 && "you are using a non initialized vector"); - - typename Derived::InnerIterator i(derived(),0); - Scalar res = 0; - while (i) - { - res += internal::conj(i.value()) * other.coeff(i.index()); - ++i; - } - return res; -} - -template -template -typename internal::traits::Scalar -SparseMatrixBase::dot(const SparseMatrixBase& other) const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) - EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - eigen_assert(size() == other.size()); - - typename Derived::InnerIterator i(derived(),0); - typename OtherDerived::InnerIterator j(other.derived(),0); - Scalar res = 0; - while (i && j) - { - if (i.index()==j.index()) - { - res += internal::conj(i.value()) * j.value(); - ++i; ++j; - } - else if (i.index() -inline typename NumTraits::Scalar>::Real -SparseMatrixBase::squaredNorm() const -{ - return internal::real((*this).cwiseAbs2().sum()); -} - -template -inline typename NumTraits::Scalar>::Real -SparseMatrixBase::norm() const -{ - return internal::sqrt(squaredNorm()); -} - -#endif // EIGEN_SPARSE_DOT_H diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseFuzzy.h b/extern/Eigen3/Eigen/src/Sparse/SparseFuzzy.h deleted file mode 100644 index f00b3d6469b..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/SparseFuzzy.h +++ /dev/null @@ -1,41 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSE_FUZZY_H -#define EIGEN_SPARSE_FUZZY_H - -// template -// template -// bool SparseMatrixBase::isApprox( -// const OtherDerived& other, -// typename NumTraits::Real prec -// ) const -// { -// const typename internal::nested::type nested(derived()); -// const typename internal::nested::type otherNested(other.derived()); -// return (nested - otherNested).cwise().abs2().sum() -// <= prec * prec * (std::min)(nested.cwise().abs2().sum(), otherNested.cwise().abs2().sum()); -// } - -#endif // EIGEN_SPARSE_FUZZY_H diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseMatrix.h b/extern/Eigen3/Eigen/src/Sparse/SparseMatrix.h deleted file mode 100644 index 0e175ec6e71..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/SparseMatrix.h +++ /dev/null @@ -1,651 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2010 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSEMATRIX_H -#define EIGEN_SPARSEMATRIX_H - -/** \ingroup Sparse_Module - * - * \class SparseMatrix - * - * \brief The main sparse matrix class - * - * This class implements a sparse matrix using the very common compressed row/column storage - * scheme. - * - * \tparam _Scalar the scalar type, i.e. the type of the coefficients - * \tparam _Options Union of bit flags controlling the storage scheme. Currently the only possibility - * is RowMajor. The default is 0 which means column-major. - * \tparam _Index the type of the indices. Default is \c int. - * - * See http://www.netlib.org/linalg/html_templates/node91.html for details on the storage scheme. - * - * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEMATRIX_PLUGIN. - */ - -namespace internal { -template -struct traits > -{ - typedef _Scalar Scalar; - typedef _Index Index; - typedef Sparse StorageKind; - typedef MatrixXpr XprKind; - enum { - RowsAtCompileTime = Dynamic, - ColsAtCompileTime = Dynamic, - MaxRowsAtCompileTime = Dynamic, - MaxColsAtCompileTime = Dynamic, - Flags = _Options | NestByRefBit | LvalueBit, - CoeffReadCost = NumTraits::ReadCost, - SupportedAccessPatterns = InnerRandomAccessPattern - }; -}; - -} // end namespace internal - -template -class SparseMatrix - : public SparseMatrixBase > -{ - public: - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseMatrix) -// using Base::operator=; - EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseMatrix, +=) - EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseMatrix, -=) - // FIXME: why are these operator already alvailable ??? - // EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(SparseMatrix, *=) - // EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(SparseMatrix, /=) - - typedef MappedSparseMatrix Map; - using Base::IsRowMajor; - typedef CompressedStorage Storage; - enum { - Options = _Options - }; - - protected: - - typedef SparseMatrix TransposedSparseMatrix; - - Index m_outerSize; - Index m_innerSize; - Index* m_outerIndex; - CompressedStorage m_data; - - public: - - inline Index rows() const { return IsRowMajor ? m_outerSize : m_innerSize; } - inline Index cols() const { return IsRowMajor ? m_innerSize : m_outerSize; } - - inline Index innerSize() const { return m_innerSize; } - inline Index outerSize() const { return m_outerSize; } - inline Index innerNonZeros(Index j) const { return m_outerIndex[j+1]-m_outerIndex[j]; } - - inline const Scalar* _valuePtr() const { return &m_data.value(0); } - inline Scalar* _valuePtr() { return &m_data.value(0); } - - inline const Index* _innerIndexPtr() const { return &m_data.index(0); } - inline Index* _innerIndexPtr() { return &m_data.index(0); } - - inline const Index* _outerIndexPtr() const { return m_outerIndex; } - inline Index* _outerIndexPtr() { return m_outerIndex; } - - inline Storage& data() { return m_data; } - inline const Storage& data() const { return m_data; } - - inline Scalar coeff(Index row, Index col) const - { - const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; - return m_data.atInRange(m_outerIndex[outer], m_outerIndex[outer+1], inner); - } - - inline Scalar& coeffRef(Index row, Index col) - { - const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; - - Index start = m_outerIndex[outer]; - Index end = m_outerIndex[outer+1]; - eigen_assert(end>=start && "you probably called coeffRef on a non finalized matrix"); - eigen_assert(end>start && "coeffRef cannot be called on a zero coefficient"); - const Index p = m_data.searchLowerIndex(start,end-1,inner); - eigen_assert((p(m_data.size()); } - - /** Preallocates \a reserveSize non zeros */ - inline void reserve(Index reserveSize) - { - m_data.reserve(reserveSize); - } - - //--- low level purely coherent filling --- - - /** \returns a reference to the non zero coefficient at position \a row, \a col assuming that: - * - the nonzero does not already exist - * - the new coefficient is the last one according to the storage order - * - * Before filling a given inner vector you must call the statVec(Index) function. - * - * After an insertion session, you should call the finalize() function. - * - * \sa insert, insertBackByOuterInner, startVec */ - inline Scalar& insertBack(Index row, Index col) - { - return insertBackByOuterInner(IsRowMajor?row:col, IsRowMajor?col:row); - } - - /** \sa insertBack, startVec */ - inline Scalar& insertBackByOuterInner(Index outer, Index inner) - { - eigen_assert(size_t(m_outerIndex[outer+1]) == m_data.size() && "Invalid ordered insertion (invalid outer index)"); - eigen_assert( (m_outerIndex[outer+1]-m_outerIndex[outer]==0 || m_data.index(m_data.size()-1)=0 && m_outerIndex[previousOuter]==0) - { - m_outerIndex[previousOuter] = static_cast(m_data.size()); - --previousOuter; - } - m_outerIndex[outer+1] = m_outerIndex[outer]; - } - - // here we have to handle the tricky case where the outerIndex array - // starts with: [ 0 0 0 0 0 1 ...] and we are inserting in, e.g., - // the 2nd inner vector... - bool isLastVec = (!(previousOuter==-1 && m_data.size()!=0)) - && (size_t(m_outerIndex[outer+1]) == m_data.size()); - - size_t startId = m_outerIndex[outer]; - // FIXME let's make sure sizeof(long int) == sizeof(size_t) - size_t p = m_outerIndex[outer+1]; - ++m_outerIndex[outer+1]; - - float reallocRatio = 1; - if (m_data.allocatedSize()<=m_data.size()) - { - // if there is no preallocated memory, let's reserve a minimum of 32 elements - if (m_data.size()==0) - { - m_data.reserve(32); - } - else - { - // we need to reallocate the data, to reduce multiple reallocations - // we use a smart resize algorithm based on the current filling ratio - // in addition, we use float to avoid integers overflows - float nnzEstimate = float(m_outerIndex[outer])*float(m_outerSize)/float(outer+1); - reallocRatio = (nnzEstimate-float(m_data.size()))/float(m_data.size()); - // furthermore we bound the realloc ratio to: - // 1) reduce multiple minor realloc when the matrix is almost filled - // 2) avoid to allocate too much memory when the matrix is almost empty - reallocRatio = (std::min)((std::max)(reallocRatio,1.5f),8.f); - } - } - m_data.resize(m_data.size()+1,reallocRatio); - - if (!isLastVec) - { - if (previousOuter==-1) - { - // oops wrong guess. - // let's correct the outer offsets - for (Index k=0; k<=(outer+1); ++k) - m_outerIndex[k] = 0; - Index k=outer+1; - while(m_outerIndex[k]==0) - m_outerIndex[k++] = 1; - while (k<=m_outerSize && m_outerIndex[k]!=0) - m_outerIndex[k++]++; - p = 0; - --k; - k = m_outerIndex[k]-1; - while (k>0) - { - m_data.index(k) = m_data.index(k-1); - m_data.value(k) = m_data.value(k-1); - k--; - } - } - else - { - // we are not inserting into the last inner vec - // update outer indices: - Index j = outer+2; - while (j<=m_outerSize && m_outerIndex[j]!=0) - m_outerIndex[j++]++; - --j; - // shift data of last vecs: - Index k = m_outerIndex[j]-1; - while (k>=Index(p)) - { - m_data.index(k) = m_data.index(k-1); - m_data.value(k) = m_data.value(k-1); - k--; - } - } - } - - while ( (p > startId) && (m_data.index(p-1) > inner) ) - { - m_data.index(p) = m_data.index(p-1); - m_data.value(p) = m_data.value(p-1); - --p; - } - - m_data.index(p) = inner; - return (m_data.value(p) = 0); - } - - - - - /** Must be called after inserting a set of non zero entries. - */ - inline void finalize() - { - Index size = static_cast(m_data.size()); - Index i = m_outerSize; - // find the last filled column - while (i>=0 && m_outerIndex[i]==0) - --i; - ++i; - while (i<=m_outerSize) - { - m_outerIndex[i] = size; - ++i; - } - } - - /** Suppress all nonzeros which are smaller than \a reference under the tolerence \a epsilon */ - void prune(Scalar reference, RealScalar epsilon = NumTraits::dummy_precision()) - { - prune(default_prunning_func(reference,epsilon)); - } - - /** Suppress all nonzeros which do not satisfy the predicate \a keep. - * The functor type \a KeepFunc must implement the following function: - * \code - * bool operator() (const Index& row, const Index& col, const Scalar& value) const; - * \endcode - * \sa prune(Scalar,RealScalar) - */ - template - void prune(const KeepFunc& keep = KeepFunc()) - { - Index k = 0; - for(Index j=0; j - inline SparseMatrix(const SparseMatrixBase& other) - : m_outerSize(0), m_innerSize(0), m_outerIndex(0) - { - *this = other.derived(); - } - - /** Copy constructor */ - inline SparseMatrix(const SparseMatrix& other) - : Base(), m_outerSize(0), m_innerSize(0), m_outerIndex(0) - { - *this = other.derived(); - } - - /** Swap the content of two sparse matrices of same type (optimization) */ - inline void swap(SparseMatrix& other) - { - //EIGEN_DBG_SPARSE(std::cout << "SparseMatrix:: swap\n"); - std::swap(m_outerIndex, other.m_outerIndex); - std::swap(m_innerSize, other.m_innerSize); - std::swap(m_outerSize, other.m_outerSize); - m_data.swap(other.m_data); - } - - inline SparseMatrix& operator=(const SparseMatrix& other) - { -// std::cout << "SparseMatrix& operator=(const SparseMatrix& other)\n"; - if (other.isRValue()) - { - swap(other.const_cast_derived()); - } - else - { - resize(other.rows(), other.cols()); - memcpy(m_outerIndex, other.m_outerIndex, (m_outerSize+1)*sizeof(Index)); - m_data = other.m_data; - } - return *this; - } - - #ifndef EIGEN_PARSED_BY_DOXYGEN - template - inline SparseMatrix& operator=(const SparseSparseProduct& product) - { return Base::operator=(product); } - - template - inline SparseMatrix& operator=(const ReturnByValue& other) - { return Base::operator=(other); } - - template - inline SparseMatrix& operator=(const EigenBase& other) - { return Base::operator=(other); } - #endif - - template - EIGEN_DONT_INLINE SparseMatrix& operator=(const SparseMatrixBase& other) - { - const bool needToTranspose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); - if (needToTranspose) - { - // two passes algorithm: - // 1 - compute the number of coeffs per dest inner vector - // 2 - do the actual copy/eval - // Since each coeff of the rhs has to be evaluated twice, let's evaluate it if needed - typedef typename internal::nested::type OtherCopy; - typedef typename internal::remove_all::type _OtherCopy; - OtherCopy otherCopy(other.derived()); - - resize(other.rows(), other.cols()); - Eigen::Map > (m_outerIndex,outerSize()).setZero(); - // pass 1 - // FIXME the above copy could be merged with that pass - for (Index j=0; j::operator=(other.derived()); - } - } - - friend std::ostream & operator << (std::ostream & s, const SparseMatrix& m) - { - EIGEN_DBG_SPARSE( - s << "Nonzero entries:\n"; - for (Index i=0; i&>(m); - return s; - } - - /** Destructor */ - inline ~SparseMatrix() - { - delete[] m_outerIndex; - } - - /** Overloaded for performance */ - Scalar sum() const; - - public: - - /** \deprecated use setZero() and reserve() - * Initializes the filling process of \c *this. - * \param reserveSize approximate number of nonzeros - * Note that the matrix \c *this is zero-ed. - */ - EIGEN_DEPRECATED void startFill(Index reserveSize = 1000) - { - setZero(); - m_data.reserve(reserveSize); - } - - /** \deprecated use insert() - * Like fill() but with random inner coordinates. - */ - EIGEN_DEPRECATED Scalar& fillrand(Index row, Index col) - { - return insert(row,col); - } - - /** \deprecated use insert() - */ - EIGEN_DEPRECATED Scalar& fill(Index row, Index col) - { - const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; - - if (m_outerIndex[outer+1]==0) - { - // we start a new inner vector - Index i = outer; - while (i>=0 && m_outerIndex[i]==0) - { - m_outerIndex[i] = m_data.size(); - --i; - } - m_outerIndex[outer+1] = m_outerIndex[outer]; - } - else - { - eigen_assert(m_data.index(m_data.size()-1) -class SparseMatrix::InnerIterator -{ - public: - InnerIterator(const SparseMatrix& mat, Index outer) - : m_values(mat._valuePtr()), m_indices(mat._innerIndexPtr()), m_outer(outer), m_id(mat.m_outerIndex[outer]), m_end(mat.m_outerIndex[outer+1]) - {} - - inline InnerIterator& operator++() { m_id++; return *this; } - - inline const Scalar& value() const { return m_values[m_id]; } - inline Scalar& valueRef() { return const_cast(m_values[m_id]); } - - inline Index index() const { return m_indices[m_id]; } - inline Index outer() const { return m_outer; } - inline Index row() const { return IsRowMajor ? m_outer : index(); } - inline Index col() const { return IsRowMajor ? index() : m_outer; } - - inline operator bool() const { return (m_id < m_end); } - - protected: - const Scalar* m_values; - const Index* m_indices; - const Index m_outer; - Index m_id; - const Index m_end; -}; - -#endif // EIGEN_SPARSEMATRIX_H diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseMatrixBase.h b/extern/Eigen3/Eigen/src/Sparse/SparseMatrixBase.h deleted file mode 100644 index c01981bc935..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/SparseMatrixBase.h +++ /dev/null @@ -1,706 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSEMATRIXBASE_H -#define EIGEN_SPARSEMATRIXBASE_H - -/** \ingroup Sparse_Module - * - * \class SparseMatrixBase - * - * \brief Base class of any sparse matrices or sparse expressions - * - * \tparam Derived - * - * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEMATRIXBASE_PLUGIN. - */ -template class SparseMatrixBase : public EigenBase -{ - public: - - typedef typename internal::traits::Scalar Scalar; - typedef typename internal::packet_traits::type PacketScalar; - typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; - - typedef SparseMatrixBase StorageBaseType; - typedef EigenBase Base; - - template - Derived& operator=(const EigenBase &other) - { - other.derived().evalTo(derived()); - return derived(); - } - -// using Base::operator=; - - enum { - - RowsAtCompileTime = internal::traits::RowsAtCompileTime, - /**< The number of rows at compile-time. This is just a copy of the value provided - * by the \a Derived type. If a value is not known at compile-time, - * it is set to the \a Dynamic constant. - * \sa MatrixBase::rows(), MatrixBase::cols(), ColsAtCompileTime, SizeAtCompileTime */ - - ColsAtCompileTime = internal::traits::ColsAtCompileTime, - /**< The number of columns at compile-time. This is just a copy of the value provided - * by the \a Derived type. If a value is not known at compile-time, - * it is set to the \a Dynamic constant. - * \sa MatrixBase::rows(), MatrixBase::cols(), RowsAtCompileTime, SizeAtCompileTime */ - - - SizeAtCompileTime = (internal::size_at_compile_time::RowsAtCompileTime, - internal::traits::ColsAtCompileTime>::ret), - /**< This is equal to the number of coefficients, i.e. the number of - * rows times the number of columns, or to \a Dynamic if this is not - * known at compile-time. \sa RowsAtCompileTime, ColsAtCompileTime */ - - MaxRowsAtCompileTime = RowsAtCompileTime, - MaxColsAtCompileTime = ColsAtCompileTime, - - MaxSizeAtCompileTime = (internal::size_at_compile_time::ret), - - IsVectorAtCompileTime = RowsAtCompileTime == 1 || ColsAtCompileTime == 1, - /**< This is set to true if either the number of rows or the number of - * columns is known at compile-time to be equal to 1. Indeed, in that case, - * we are dealing with a column-vector (if there is only one column) or with - * a row-vector (if there is only one row). */ - - Flags = internal::traits::Flags, - /**< This stores expression \ref flags flags which may or may not be inherited by new expressions - * constructed from this one. See the \ref flags "list of flags". - */ - - CoeffReadCost = internal::traits::CoeffReadCost, - /**< This is a rough measure of how expensive it is to read one coefficient from - * this expression. - */ - - IsRowMajor = Flags&RowMajorBit ? 1 : 0, - - #ifndef EIGEN_PARSED_BY_DOXYGEN - _HasDirectAccess = (int(Flags)&DirectAccessBit) ? 1 : 0 // workaround sunCC - #endif - }; - - /* \internal the return type of MatrixBase::conjugate() */ -// typedef typename internal::conditional::IsComplex, -// const SparseCwiseUnaryOp, Derived>, -// const Derived& -// >::type ConjugateReturnType; - /* \internal the return type of MatrixBase::real() */ -// typedef SparseCwiseUnaryOp, Derived> RealReturnType; - /* \internal the return type of MatrixBase::imag() */ -// typedef SparseCwiseUnaryOp, Derived> ImagReturnType; - /** \internal the return type of MatrixBase::adjoint() */ - typedef typename internal::conditional::IsComplex, - CwiseUnaryOp, Eigen::Transpose >, - Transpose - >::type AdjointReturnType; - - - typedef SparseMatrix PlainObject; - -#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::SparseMatrixBase -# include "../plugins/CommonCwiseUnaryOps.h" -# include "../plugins/CommonCwiseBinaryOps.h" -# include "../plugins/MatrixCwiseUnaryOps.h" -# include "../plugins/MatrixCwiseBinaryOps.h" -# ifdef EIGEN_SPARSEMATRIXBASE_PLUGIN -# include EIGEN_SPARSEMATRIXBASE_PLUGIN -# endif -# undef EIGEN_CURRENT_STORAGE_BASE_CLASS -#undef EIGEN_CURRENT_STORAGE_BASE_CLASS - -#ifndef EIGEN_PARSED_BY_DOXYGEN - /** This is the "real scalar" type; if the \a Scalar type is already real numbers - * (e.g. int, float or double) then \a RealScalar is just the same as \a Scalar. If - * \a Scalar is \a std::complex then RealScalar is \a T. - * - * \sa class NumTraits - */ - typedef typename NumTraits::Real RealScalar; - - /** \internal the return type of coeff() - */ - typedef typename internal::conditional<_HasDirectAccess, const Scalar&, Scalar>::type CoeffReturnType; - - /** \internal Represents a matrix with all coefficients equal to one another*/ - typedef CwiseNullaryOp,Matrix > ConstantReturnType; - - /** type of the equivalent square matrix */ - typedef Matrix SquareMatrixType; - - inline const Derived& derived() const { return *static_cast(this); } - inline Derived& derived() { return *static_cast(this); } - inline Derived& const_cast_derived() const - { return *static_cast(const_cast(this)); } -#endif // not EIGEN_PARSED_BY_DOXYGEN - - /** \returns the number of rows. \sa cols(), RowsAtCompileTime */ - inline Index rows() const { return derived().rows(); } - /** \returns the number of columns. \sa rows(), ColsAtCompileTime*/ - inline Index cols() const { return derived().cols(); } - /** \returns the number of coefficients, which is \a rows()*cols(). - * \sa rows(), cols(), SizeAtCompileTime. */ - inline Index size() const { return rows() * cols(); } - /** \returns the number of nonzero coefficients which is in practice the number - * of stored coefficients. */ - inline Index nonZeros() const { return derived().nonZeros(); } - /** \returns true if either the number of rows or the number of columns is equal to 1. - * In other words, this function returns - * \code rows()==1 || cols()==1 \endcode - * \sa rows(), cols(), IsVectorAtCompileTime. */ - inline bool isVector() const { return rows()==1 || cols()==1; } - /** \returns the size of the storage major dimension, - * i.e., the number of columns for a columns major matrix, and the number of rows otherwise */ - Index outerSize() const { return (int(Flags)&RowMajorBit) ? this->rows() : this->cols(); } - /** \returns the size of the inner dimension according to the storage order, - * i.e., the number of rows for a columns major matrix, and the number of cols otherwise */ - Index innerSize() const { return (int(Flags)&RowMajorBit) ? this->cols() : this->rows(); } - - bool isRValue() const { return m_isRValue; } - Derived& markAsRValue() { m_isRValue = true; return derived(); } - - SparseMatrixBase() : m_isRValue(false) { /* TODO check flags */ } - - inline Derived& operator=(const Derived& other) - { -// std::cout << "Derived& operator=(const Derived& other)\n"; -// if (other.isRValue()) -// derived().swap(other.const_cast_derived()); -// else - this->operator=(other); - return derived(); - } - - template - Derived& operator=(const ReturnByValue& other) - { - other.evalTo(derived()); - return derived(); - } - - - template - inline void assignGeneric(const OtherDerived& other) - { -// std::cout << "Derived& operator=(const MatrixBase& other)\n"; - //const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); - eigen_assert(( ((internal::traits::SupportedAccessPatterns&OuterRandomAccessPattern)==OuterRandomAccessPattern) || - (!((Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit)))) && - "the transpose operation is supposed to be handled in SparseMatrix::operator="); - - enum { Flip = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit) }; - - const Index outerSize = other.outerSize(); - //typedef typename internal::conditional, Derived>::type TempType; - // thanks to shallow copies, we always eval to a tempary - Derived temp(other.rows(), other.cols()); - - temp.reserve((std::max)(this->rows(),this->cols())*2); - for (Index j=0; j - inline Derived& operator=(const SparseMatrixBase& other) - { -// std::cout << typeid(OtherDerived).name() << "\n"; -// std::cout << Flags << " " << OtherDerived::Flags << "\n"; - const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); -// std::cout << "eval transpose = " << transpose << "\n"; - const Index outerSize = (int(OtherDerived::Flags) & RowMajorBit) ? other.rows() : other.cols(); - if ((!transpose) && other.isRValue()) - { - // eval without temporary - derived().resize(other.rows(), other.cols()); - derived().setZero(); - derived().reserve((std::max)(this->rows(),this->cols())*2); - for (Index j=0; j - inline Derived& operator=(const SparseSparseProduct& product); - - template - inline void _experimentalNewProduct(const Lhs& lhs, const Rhs& rhs); - - friend std::ostream & operator << (std::ostream & s, const SparseMatrixBase& m) - { - if (Flags&RowMajorBit) - { - for (Index row=0; row trans = m.derived(); - s << trans; - } - } - return s; - } - -// const SparseCwiseUnaryOp::Scalar>,Derived> operator-() const; - -// template -// const CwiseBinaryOp::Scalar>, Derived, OtherDerived> -// operator+(const SparseMatrixBase &other) const; - -// template -// const CwiseBinaryOp::Scalar>, Derived, OtherDerived> -// operator-(const SparseMatrixBase &other) const; - - template - Derived& operator+=(const SparseMatrixBase& other); - template - Derived& operator-=(const SparseMatrixBase& other); - -// template -// Derived& operator+=(const Flagged, 0, EvalBeforeNestingBit | EvalBeforeAssigningBit>& other); - - Derived& operator*=(const Scalar& other); - Derived& operator/=(const Scalar& other); - - #define EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE \ - CwiseBinaryOp< \ - internal::scalar_product_op< \ - typename internal::scalar_product_traits< \ - typename internal::traits::Scalar, \ - typename internal::traits::Scalar \ - >::ReturnType \ - >, \ - Derived, \ - OtherDerived \ - > - - template - EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE - cwiseProduct(const MatrixBase &other) const; - -// const SparseCwiseUnaryOp::Scalar>, Derived> -// operator*(const Scalar& scalar) const; -// const SparseCwiseUnaryOp::Scalar>, Derived> -// operator/(const Scalar& scalar) const; - -// inline friend const SparseCwiseUnaryOp::Scalar>, Derived> -// operator*(const Scalar& scalar, const SparseMatrixBase& matrix) -// { return matrix*scalar; } - - - // sparse * sparse - template - const typename SparseSparseProductReturnType::Type - operator*(const SparseMatrixBase &other) const; - - // sparse * diagonal - template - const SparseDiagonalProduct - operator*(const DiagonalBase &other) const; - - // diagonal * sparse - template friend - const SparseDiagonalProduct - operator*(const DiagonalBase &lhs, const SparseMatrixBase& rhs) - { return SparseDiagonalProduct(lhs.derived(), rhs.derived()); } - - /** dense * sparse (return a dense object unless it is an outer product) */ - template friend - const typename DenseSparseProductReturnType::Type - operator*(const MatrixBase& lhs, const Derived& rhs) - { return typename DenseSparseProductReturnType::Type(lhs.derived(),rhs); } - - /** sparse * dense (returns a dense object unless it is an outer product) */ - template - const typename SparseDenseProductReturnType::Type - operator*(const MatrixBase &other) const; - - template - Derived& operator*=(const SparseMatrixBase& other); - - #ifdef EIGEN2_SUPPORT - // deprecated - template - typename internal::plain_matrix_type_column_major::type - solveTriangular(const MatrixBase& other) const; - - // deprecated - template - void solveTriangularInPlace(MatrixBase& other) const; -// template -// void solveTriangularInPlace(SparseMatrixBase& other) const; - #endif // EIGEN2_SUPPORT - - template - inline const SparseTriangularView triangularView() const; - - template inline const SparseSelfAdjointView selfadjointView() const; - template inline SparseSelfAdjointView selfadjointView(); - - template Scalar dot(const MatrixBase& other) const; - template Scalar dot(const SparseMatrixBase& other) const; - RealScalar squaredNorm() const; - RealScalar norm() const; -// const PlainObject normalized() const; -// void normalize(); - - Transpose transpose() { return derived(); } - const Transpose transpose() const { return derived(); } - // void transposeInPlace(); - const AdjointReturnType adjoint() const { return transpose(); } - - // sub-vector - SparseInnerVectorSet row(Index i); - const SparseInnerVectorSet row(Index i) const; - SparseInnerVectorSet col(Index j); - const SparseInnerVectorSet col(Index j) const; - SparseInnerVectorSet innerVector(Index outer); - const SparseInnerVectorSet innerVector(Index outer) const; - - // set of sub-vectors - SparseInnerVectorSet subrows(Index start, Index size); - const SparseInnerVectorSet subrows(Index start, Index size) const; - SparseInnerVectorSet subcols(Index start, Index size); - const SparseInnerVectorSet subcols(Index start, Index size) const; - SparseInnerVectorSet innerVectors(Index outerStart, Index outerSize); - const SparseInnerVectorSet innerVectors(Index outerStart, Index outerSize) const; - -// typename BlockReturnType::Type block(int startRow, int startCol, int blockRows, int blockCols); -// const typename BlockReturnType::Type -// block(int startRow, int startCol, int blockRows, int blockCols) const; -// -// typename BlockReturnType::SubVectorType segment(int start, int size); -// const typename BlockReturnType::SubVectorType segment(int start, int size) const; -// -// typename BlockReturnType::SubVectorType start(int size); -// const typename BlockReturnType::SubVectorType start(int size) const; -// -// typename BlockReturnType::SubVectorType end(int size); -// const typename BlockReturnType::SubVectorType end(int size) const; -// -// template -// typename BlockReturnType::Type block(int startRow, int startCol); -// template -// const typename BlockReturnType::Type block(int startRow, int startCol) const; - -// template typename BlockReturnType::SubVectorType start(void); -// template const typename BlockReturnType::SubVectorType start() const; - -// template typename BlockReturnType::SubVectorType end(); -// template const typename BlockReturnType::SubVectorType end() const; - -// template typename BlockReturnType::SubVectorType segment(int start); -// template const typename BlockReturnType::SubVectorType segment(int start) const; - -// Diagonal diagonal(); -// const Diagonal diagonal() const; - -// template Part part(); -// template const Part part() const; - - -// static const ConstantReturnType Constant(int rows, int cols, const Scalar& value); -// static const ConstantReturnType Constant(int size, const Scalar& value); -// static const ConstantReturnType Constant(const Scalar& value); - -// template -// static const CwiseNullaryOp NullaryExpr(int rows, int cols, const CustomNullaryOp& func); -// template -// static const CwiseNullaryOp NullaryExpr(int size, const CustomNullaryOp& func); -// template -// static const CwiseNullaryOp NullaryExpr(const CustomNullaryOp& func); - -// static const ConstantReturnType Zero(int rows, int cols); -// static const ConstantReturnType Zero(int size); -// static const ConstantReturnType Zero(); -// static const ConstantReturnType Ones(int rows, int cols); -// static const ConstantReturnType Ones(int size); -// static const ConstantReturnType Ones(); -// static const IdentityReturnType Identity(); -// static const IdentityReturnType Identity(int rows, int cols); -// static const BasisReturnType Unit(int size, int i); -// static const BasisReturnType Unit(int i); -// static const BasisReturnType UnitX(); -// static const BasisReturnType UnitY(); -// static const BasisReturnType UnitZ(); -// static const BasisReturnType UnitW(); - -// const DiagonalMatrix asDiagonal() const; - -// Derived& setConstant(const Scalar& value); -// Derived& setZero(); -// Derived& setOnes(); -// Derived& setRandom(); -// Derived& setIdentity(); - - /** \internal use operator= */ - template - void evalTo(MatrixBase& dst) const - { - dst.setZero(); - for (Index j=0; j toDense() const - { - return derived(); - } - - template - bool isApprox(const SparseMatrixBase& other, - RealScalar prec = NumTraits::dummy_precision()) const - { return toDense().isApprox(other.toDense(),prec); } - - template - bool isApprox(const MatrixBase& other, - RealScalar prec = NumTraits::dummy_precision()) const - { return toDense().isApprox(other,prec); } -// bool isMuchSmallerThan(const RealScalar& other, -// RealScalar prec = NumTraits::dummy_precision()) const; -// template -// bool isMuchSmallerThan(const MatrixBase& other, -// RealScalar prec = NumTraits::dummy_precision()) const; - -// bool isApproxToConstant(const Scalar& value, RealScalar prec = NumTraits::dummy_precision()) const; -// bool isZero(RealScalar prec = NumTraits::dummy_precision()) const; -// bool isOnes(RealScalar prec = NumTraits::dummy_precision()) const; -// bool isIdentity(RealScalar prec = NumTraits::dummy_precision()) const; -// bool isDiagonal(RealScalar prec = NumTraits::dummy_precision()) const; - -// bool isUpper(RealScalar prec = NumTraits::dummy_precision()) const; -// bool isLower(RealScalar prec = NumTraits::dummy_precision()) const; - -// template -// bool isOrthogonal(const MatrixBase& other, -// RealScalar prec = NumTraits::dummy_precision()) const; -// bool isUnitary(RealScalar prec = NumTraits::dummy_precision()) const; - -// template -// inline bool operator==(const MatrixBase& other) const -// { return (cwise() == other).all(); } - -// template -// inline bool operator!=(const MatrixBase& other) const -// { return (cwise() != other).any(); } - - -// template -// const SparseCwiseUnaryOp::Scalar, NewType>, Derived> cast() const; - - /** \returns the matrix or vector obtained by evaluating this expression. - * - * Notice that in the case of a plain matrix or vector (not an expression) this function just returns - * a const reference, in order to avoid a useless copy. - */ - inline const typename internal::eval::type eval() const - { return typename internal::eval::type(derived()); } - -// template -// void swap(MatrixBase const & other); - -// template -// const SparseFlagged marked() const; -// const Flagged lazy() const; - - /** \returns number of elements to skip to pass from one row (resp. column) to another - * for a row-major (resp. column-major) matrix. - * Combined with coeffRef() and the \ref flags flags, it allows a direct access to the data - * of the underlying matrix. - */ -// inline int stride(void) const { return derived().stride(); } - -// FIXME -// ConjugateReturnType conjugate() const; -// const RealReturnType real() const; -// const ImagReturnType imag() const; - -// template -// const SparseCwiseUnaryOp unaryExpr(const CustomUnaryOp& func = CustomUnaryOp()) const; - -// template -// const CwiseBinaryOp -// binaryExpr(const MatrixBase &other, const CustomBinaryOp& func = CustomBinaryOp()) const; - - - Scalar sum() const; -// Scalar trace() const; - -// typename internal::traits::Scalar minCoeff() const; -// typename internal::traits::Scalar maxCoeff() const; - -// typename internal::traits::Scalar minCoeff(int* row, int* col = 0) const; -// typename internal::traits::Scalar maxCoeff(int* row, int* col = 0) const; - -// template -// typename internal::result_of::Scalar)>::type -// redux(const BinaryOp& func) const; - -// template -// void visit(Visitor& func) const; - - -// const SparseCwise cwise() const; -// SparseCwise cwise(); - -// inline const WithFormat format(const IOFormat& fmt) const; - -/////////// Array module /////////// - /* - bool all(void) const; - bool any(void) const; - - const VectorwiseOp rowwise() const; - const VectorwiseOp colwise() const; - - static const CwiseNullaryOp,Derived> Random(int rows, int cols); - static const CwiseNullaryOp,Derived> Random(int size); - static const CwiseNullaryOp,Derived> Random(); - - template - const Select - select(const MatrixBase& thenMatrix, - const MatrixBase& elseMatrix) const; - - template - inline const Select - select(const MatrixBase& thenMatrix, typename ThenDerived::Scalar elseScalar) const; - - template - inline const Select - select(typename ElseDerived::Scalar thenScalar, const MatrixBase& elseMatrix) const; - - template RealScalar lpNorm() const; - */ - - -// template -// Scalar dot(const MatrixBase& other) const -// { -// EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) -// EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) -// EIGEN_STATIC_ASSERT((internal::is_same::value), -// YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) -// -// eigen_assert(derived().size() == other.size()); -// // short version, but the assembly looks more complicated because -// // of the CwiseBinaryOp iterator complexity -// // return res = (derived().cwise() * other.derived().conjugate()).sum(); -// -// // optimized, generic version -// typename Derived::InnerIterator i(derived(),0); -// typename OtherDerived::InnerIterator j(other.derived(),0); -// Scalar res = 0; -// while (i && j) -// { -// if (i.index()==j.index()) -// { -// // std::cerr << i.value() << " * " << j.value() << "\n"; -// res += i.value() * internal::conj(j.value()); -// ++i; ++j; -// } -// else if (i.index() -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSEPRODUCT_H -#define EIGEN_SPARSEPRODUCT_H - -template -struct SparseSparseProductReturnType -{ - typedef typename internal::traits::Scalar Scalar; - enum { - LhsRowMajor = internal::traits::Flags & RowMajorBit, - RhsRowMajor = internal::traits::Flags & RowMajorBit, - TransposeRhs = (!LhsRowMajor) && RhsRowMajor, - TransposeLhs = LhsRowMajor && (!RhsRowMajor) - }; - - typedef typename internal::conditional, - const typename internal::nested::type>::type LhsNested; - - typedef typename internal::conditional, - const typename internal::nested::type>::type RhsNested; - - typedef SparseSparseProduct Type; -}; - -namespace internal { -template -struct traits > -{ - typedef MatrixXpr XprKind; - // clean the nested types: - typedef typename remove_all::type _LhsNested; - typedef typename remove_all::type _RhsNested; - typedef typename _LhsNested::Scalar Scalar; - typedef typename promote_index_type::Index, - typename traits<_RhsNested>::Index>::type Index; - - enum { - LhsCoeffReadCost = _LhsNested::CoeffReadCost, - RhsCoeffReadCost = _RhsNested::CoeffReadCost, - LhsFlags = _LhsNested::Flags, - RhsFlags = _RhsNested::Flags, - - RowsAtCompileTime = _LhsNested::RowsAtCompileTime, - ColsAtCompileTime = _RhsNested::ColsAtCompileTime, - MaxRowsAtCompileTime = _LhsNested::MaxRowsAtCompileTime, - MaxColsAtCompileTime = _RhsNested::MaxColsAtCompileTime, - - InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(_LhsNested::ColsAtCompileTime, _RhsNested::RowsAtCompileTime), - - EvalToRowMajor = (RhsFlags & LhsFlags & RowMajorBit), - - RemovedBits = ~(EvalToRowMajor ? 0 : RowMajorBit), - - Flags = (int(LhsFlags | RhsFlags) & HereditaryBits & RemovedBits) - | EvalBeforeAssigningBit - | EvalBeforeNestingBit, - - CoeffReadCost = Dynamic - }; - - typedef Sparse StorageKind; -}; - -} // end namespace internal - -template -class SparseSparseProduct : internal::no_assignment_operator, - public SparseMatrixBase > -{ - public: - - typedef SparseMatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(SparseSparseProduct) - - private: - - typedef typename internal::traits::_LhsNested _LhsNested; - typedef typename internal::traits::_RhsNested _RhsNested; - - public: - - template - EIGEN_STRONG_INLINE SparseSparseProduct(const Lhs& lhs, const Rhs& rhs) - : m_lhs(lhs), m_rhs(rhs) - { - eigen_assert(lhs.cols() == rhs.rows()); - - enum { - ProductIsValid = _LhsNested::ColsAtCompileTime==Dynamic - || _RhsNested::RowsAtCompileTime==Dynamic - || int(_LhsNested::ColsAtCompileTime)==int(_RhsNested::RowsAtCompileTime), - AreVectors = _LhsNested::IsVectorAtCompileTime && _RhsNested::IsVectorAtCompileTime, - SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(_LhsNested,_RhsNested) - }; - // note to the lost user: - // * for a dot product use: v1.dot(v2) - // * for a coeff-wise product use: v1.cwise()*v2 - EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), - INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) - EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), - INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) - EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) - } - - EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); } - - EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; } - EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; } - - protected: - LhsNested m_lhs; - RhsNested m_rhs; -}; - -#endif // EIGEN_SPARSEPRODUCT_H diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseRedux.h b/extern/Eigen3/Eigen/src/Sparse/SparseRedux.h deleted file mode 100644 index afc49de7aad..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/SparseRedux.h +++ /dev/null @@ -1,56 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSEREDUX_H -#define EIGEN_SPARSEREDUX_H - -template -typename internal::traits::Scalar -SparseMatrixBase::sum() const -{ - eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); - Scalar res = 0; - for (Index j=0; j -typename internal::traits >::Scalar -SparseMatrix<_Scalar,_Options,_Index>::sum() const -{ - eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); - return Matrix::Map(&m_data.value(0), m_data.size()).sum(); -} - -template -typename internal::traits >::Scalar -SparseVector<_Scalar,_Options,_Index>::sum() const -{ - eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); - return Matrix::Map(&m_data.value(0), m_data.size()).sum(); -} - -#endif // EIGEN_SPARSEREDUX_H diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseSelfAdjointView.h b/extern/Eigen3/Eigen/src/Sparse/SparseSelfAdjointView.h deleted file mode 100644 index d82044c789c..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/SparseSelfAdjointView.h +++ /dev/null @@ -1,454 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSE_SELFADJOINTVIEW_H -#define EIGEN_SPARSE_SELFADJOINTVIEW_H - -/** \class SparseSelfAdjointView - * - * - * \brief Pseudo expression to manipulate a triangular sparse matrix as a selfadjoint matrix. - * - * \param MatrixType the type of the dense matrix storing the coefficients - * \param UpLo can be either \c #Lower or \c #Upper - * - * This class is an expression of a sefladjoint matrix from a triangular part of a matrix - * with given dense storage of the coefficients. It is the return type of MatrixBase::selfadjointView() - * and most of the time this is the only way that it is used. - * - * \sa SparseMatrixBase::selfadjointView() - */ -template -class SparseSelfAdjointTimeDenseProduct; - -template -class DenseTimeSparseSelfAdjointProduct; - -template -class SparseSymmetricPermutationProduct; - -namespace internal { - -template -struct traits > : traits { -}; - -template -void permute_symm_to_symm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm = 0); - -template -void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm = 0); - -} - -template class SparseSelfAdjointView - : public EigenBase > -{ - public: - - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::Index Index; - typedef Matrix VectorI; - typedef typename MatrixType::Nested MatrixTypeNested; - typedef typename internal::remove_all::type _MatrixTypeNested; - - inline SparseSelfAdjointView(const MatrixType& matrix) : m_matrix(matrix) - { - eigen_assert(rows()==cols() && "SelfAdjointView is only for squared matrices"); - } - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - - /** \internal \returns a reference to the nested matrix */ - const _MatrixTypeNested& matrix() const { return m_matrix; } - _MatrixTypeNested& matrix() { return m_matrix.const_cast_derived(); } - - /** Efficient sparse self-adjoint matrix times dense vector/matrix product */ - template - SparseSelfAdjointTimeDenseProduct - operator*(const MatrixBase& rhs) const - { - return SparseSelfAdjointTimeDenseProduct(m_matrix, rhs.derived()); - } - - /** Efficient dense vector/matrix times sparse self-adjoint matrix product */ - template friend - DenseTimeSparseSelfAdjointProduct - operator*(const MatrixBase& lhs, const SparseSelfAdjointView& rhs) - { - return DenseTimeSparseSelfAdjointProduct(lhs.derived(), rhs.m_matrix); - } - - /** Perform a symmetric rank K update of the selfadjoint matrix \c *this: - * \f$ this = this + \alpha ( u u^* ) \f$ where \a u is a vector or matrix. - * - * \returns a reference to \c *this - * - * Note that it is faster to set alpha=0 than initializing the matrix to zero - * and then keep the default value alpha=1. - * - * To perform \f$ this = this + \alpha ( u^* u ) \f$ you can simply - * call this function with u.adjoint(). - */ - template - SparseSelfAdjointView& rankUpdate(const SparseMatrixBase& u, Scalar alpha = Scalar(1)); - - /** \internal triggered by sparse_matrix = SparseSelfadjointView; */ - template void evalTo(SparseMatrix& _dest) const - { - internal::permute_symm_to_fullsymm(m_matrix, _dest); - } - - template void evalTo(DynamicSparseMatrix& _dest) const - { - // TODO directly evaluate into _dest; - SparseMatrix tmp(_dest.rows(),_dest.cols()); - internal::permute_symm_to_fullsymm(m_matrix, tmp); - _dest = tmp; - } - - /** \returns an expression of P^-1 H P */ - SparseSymmetricPermutationProduct<_MatrixTypeNested,UpLo> twistedBy(const PermutationMatrix& perm) const - { - return SparseSymmetricPermutationProduct<_MatrixTypeNested,UpLo>(m_matrix, perm); - } - - template - SparseSelfAdjointView& operator=(const SparseSymmetricPermutationProduct& permutedMatrix) - { - permutedMatrix.evalTo(*this); - return *this; - } - - - // const SparseLLT llt() const; - // const SparseLDLT ldlt() const; - - protected: - - const typename MatrixType::Nested m_matrix; - mutable VectorI m_countPerRow; - mutable VectorI m_countPerCol; -}; - -/*************************************************************************** -* Implementation of SparseMatrixBase methods -***************************************************************************/ - -template -template -const SparseSelfAdjointView SparseMatrixBase::selfadjointView() const -{ - return derived(); -} - -template -template -SparseSelfAdjointView SparseMatrixBase::selfadjointView() -{ - return derived(); -} - -/*************************************************************************** -* Implementation of SparseSelfAdjointView methods -***************************************************************************/ - -template -template -SparseSelfAdjointView& -SparseSelfAdjointView::rankUpdate(const SparseMatrixBase& u, Scalar alpha) -{ - SparseMatrix tmp = u * u.adjoint(); - if(alpha==Scalar(0)) - m_matrix.const_cast_derived() = tmp.template triangularView(); - else - m_matrix.const_cast_derived() += alpha * tmp.template triangularView(); - - return *this; -} - -/*************************************************************************** -* Implementation of sparse self-adjoint time dense matrix -***************************************************************************/ - -namespace internal { -template -struct traits > - : traits, Lhs, Rhs> > -{ - typedef Dense StorageKind; -}; -} - -template -class SparseSelfAdjointTimeDenseProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(SparseSelfAdjointTimeDenseProduct) - - SparseSelfAdjointTimeDenseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - {} - - template void scaleAndAddTo(Dest& dest, Scalar alpha) const - { - // TODO use alpha - eigen_assert(alpha==Scalar(1) && "alpha != 1 is not implemented yet, sorry"); - typedef typename internal::remove_all::type _Lhs; - typedef typename internal::remove_all::type _Rhs; - typedef typename _Lhs::InnerIterator LhsInnerIterator; - enum { - LhsIsRowMajor = (_Lhs::Flags&RowMajorBit)==RowMajorBit, - ProcessFirstHalf = - ((UpLo&(Upper|Lower))==(Upper|Lower)) - || ( (UpLo&Upper) && !LhsIsRowMajor) - || ( (UpLo&Lower) && LhsIsRowMajor), - ProcessSecondHalf = !ProcessFirstHalf - }; - for (Index j=0; j dest_j(dest.row(LhsIsRowMajor ? j : 0)); - for(; (ProcessFirstHalf ? i && i.index() < j : i) ; ++i) - { - Index a = LhsIsRowMajor ? j : i.index(); - Index b = LhsIsRowMajor ? i.index() : j; - typename Lhs::Scalar v = i.value(); - dest.row(a) += (v) * m_rhs.row(b); - dest.row(b) += internal::conj(v) * m_rhs.row(a); - } - if (ProcessFirstHalf && i && (i.index()==j)) - dest.row(j) += i.value() * m_rhs.row(j); - } - } - - private: - SparseSelfAdjointTimeDenseProduct& operator=(const SparseSelfAdjointTimeDenseProduct&); -}; - -namespace internal { -template -struct traits > - : traits, Lhs, Rhs> > -{}; -} - -template -class DenseTimeSparseSelfAdjointProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(DenseTimeSparseSelfAdjointProduct) - - DenseTimeSparseSelfAdjointProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - {} - - template void scaleAndAddTo(Dest& /*dest*/, Scalar /*alpha*/) const - { - // TODO - } - - private: - DenseTimeSparseSelfAdjointProduct& operator=(const DenseTimeSparseSelfAdjointProduct&); -}; - -/*************************************************************************** -* Implementation of symmetric copies and permutations -***************************************************************************/ -namespace internal { - -template -struct traits > : traits { -}; - -template -void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm) -{ - typedef typename MatrixType::Index Index; - typedef typename MatrixType::Scalar Scalar; - typedef SparseMatrix Dest; - typedef Matrix VectorI; - - Dest& dest(_dest.derived()); - enum { - StorageOrderMatch = int(Dest::IsRowMajor) == int(MatrixType::IsRowMajor) - }; - eigen_assert(perm==0); - Index size = mat.rows(); - VectorI count; - count.resize(size); - count.setZero(); - dest.resize(size,size); - for(Index j = 0; jj) || (UpLo==Upper && ij) || (UpLo==Upper && i -void permute_symm_to_symm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm) -{ - typedef typename MatrixType::Index Index; - typedef typename MatrixType::Scalar Scalar; - typedef SparseMatrix Dest; - Dest& dest(_dest.derived()); - typedef Matrix VectorI; - //internal::conj_if cj; - - Index size = mat.rows(); - VectorI count(size); - count.setZero(); - dest.resize(size,size); - for(Index j = 0; jj)) - continue; - - Index ip = perm ? perm[i] : i; - count[DstUpLo==Lower ? (std::min)(ip,jp) : (std::max)(ip,jp)]++; - } - } - dest._outerIndexPtr()[0] = 0; - for(Index j=0; jj)) - continue; - - Index ip = perm? perm[i] : i; - Index k = count[DstUpLo==Lower ? (std::min)(ip,jp) : (std::max)(ip,jp)]++; - dest._innerIndexPtr()[k] = DstUpLo==Lower ? (std::max)(ip,jp) : (std::min)(ip,jp); - - if((DstUpLo==Lower && ipjp)) - dest._valuePtr()[k] = conj(it.value()); - else - dest._valuePtr()[k] = it.value(); - } - } -} - -} - -template -class SparseSymmetricPermutationProduct - : public EigenBase > -{ - typedef PermutationMatrix Perm; - public: - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::Index Index; - typedef Matrix VectorI; - typedef typename MatrixType::Nested MatrixTypeNested; - typedef typename internal::remove_all::type _MatrixTypeNested; - - SparseSymmetricPermutationProduct(const MatrixType& mat, const Perm& perm) - : m_matrix(mat), m_perm(perm) - {} - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - - template void evalTo(SparseMatrix& _dest) const - { - internal::permute_symm_to_fullsymm(m_matrix,_dest,m_perm.indices().data()); - } - - template void evalTo(SparseSelfAdjointView& dest) const - { - internal::permute_symm_to_symm(m_matrix,dest.matrix(),m_perm.indices().data()); - } - - protected: - const MatrixTypeNested m_matrix; - const Perm& m_perm; - -}; - -#endif // EIGEN_SPARSE_SELFADJOINTVIEW_H diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseSparseProduct.h b/extern/Eigen3/Eigen/src/Sparse/SparseSparseProduct.h deleted file mode 100644 index 19abcd1f8e4..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/SparseSparseProduct.h +++ /dev/null @@ -1,401 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2010 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSESPARSEPRODUCT_H -#define EIGEN_SPARSESPARSEPRODUCT_H - -namespace internal { - -template -static void sparse_product_impl2(const Lhs& lhs, const Rhs& rhs, ResultType& res) -{ - typedef typename remove_all::type::Scalar Scalar; - typedef typename remove_all::type::Index Index; - - // make sure to call innerSize/outerSize since we fake the storage order. - Index rows = lhs.innerSize(); - Index cols = rhs.outerSize(); - eigen_assert(lhs.outerSize() == rhs.innerSize()); - - std::vector mask(rows,false); - Matrix values(rows); - Matrix indices(rows); - - // estimate the number of non zero entries - float ratioLhs = float(lhs.nonZeros())/(float(lhs.rows())*float(lhs.cols())); - float avgNnzPerRhsColumn = float(rhs.nonZeros())/float(cols); - float ratioRes = (std::min)(ratioLhs * avgNnzPerRhsColumn, 1.f); - -// int t200 = rows/(log2(200)*1.39); -// int t = (rows*100)/139; - - res.resize(rows, cols); - res.reserve(Index(ratioRes*rows*cols)); - // we compute each column of the result, one after the other - for (Index j=0; j use a quick sort - // otherwise => loop through the entire vector - // In order to avoid to perform an expensive log2 when the - // result is clearly very sparse we use a linear bound up to 200. -// if((nnz<200 && nnz1) std::sort(indices.data(),indices.data()+nnz); -// for(int k=0; k -static void sparse_product_impl(const Lhs& lhs, const Rhs& rhs, ResultType& res) -{ -// return sparse_product_impl2(lhs,rhs,res); - - typedef typename remove_all::type::Scalar Scalar; - typedef typename remove_all::type::Index Index; - - // make sure to call innerSize/outerSize since we fake the storage order. - Index rows = lhs.innerSize(); - Index cols = rhs.outerSize(); - //int size = lhs.outerSize(); - eigen_assert(lhs.outerSize() == rhs.innerSize()); - - // allocate a temporary buffer - AmbiVector tempVector(rows); - - // estimate the number of non zero entries - float ratioLhs = float(lhs.nonZeros())/(float(lhs.rows())*float(lhs.cols())); - float avgNnzPerRhsColumn = float(rhs.nonZeros())/float(cols); - float ratioRes = (std::min)(ratioLhs * avgNnzPerRhsColumn, 1.f); - - // mimics a resizeByInnerOuter: - if(ResultType::IsRowMajor) - res.resize(cols, rows); - else - res.resize(rows, cols); - - res.reserve(Index(ratioRes*rows*cols)); - for (Index j=0; j::Iterator it(tempVector); it; ++it) - res.insertBackByOuterInner(j,it.index()) = it.value(); - } - res.finalize(); -} - -template::Flags&RowMajorBit, - int RhsStorageOrder = traits::Flags&RowMajorBit, - int ResStorageOrder = traits::Flags&RowMajorBit> -struct sparse_product_selector; - -template -struct sparse_product_selector -{ - typedef typename traits::type>::Scalar Scalar; - - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { -// std::cerr << __LINE__ << "\n"; - typename remove_all::type _res(res.rows(), res.cols()); - sparse_product_impl(lhs, rhs, _res); - res.swap(_res); - } -}; - -template -struct sparse_product_selector -{ - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { -// std::cerr << __LINE__ << "\n"; - // we need a col-major matrix to hold the result - typedef SparseMatrix SparseTemporaryType; - SparseTemporaryType _res(res.rows(), res.cols()); - sparse_product_impl(lhs, rhs, _res); - res = _res; - } -}; - -template -struct sparse_product_selector -{ - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { -// std::cerr << __LINE__ << "\n"; - // let's transpose the product to get a column x column product - typename remove_all::type _res(res.rows(), res.cols()); - sparse_product_impl(rhs, lhs, _res); - res.swap(_res); - } -}; - -template -struct sparse_product_selector -{ - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { -// std::cerr << "here...\n"; - typedef SparseMatrix ColMajorMatrix; - ColMajorMatrix colLhs(lhs); - ColMajorMatrix colRhs(rhs); -// std::cerr << "more...\n"; - sparse_product_impl(colLhs, colRhs, res); -// std::cerr << "OK.\n"; - - // let's transpose the product to get a column x column product - -// typedef SparseMatrix SparseTemporaryType; -// SparseTemporaryType _res(res.cols(), res.rows()); -// sparse_product_impl(rhs, lhs, _res); -// res = _res.transpose(); - } -}; - -// NOTE the 2 others cases (col row *) must never occur since they are caught -// by ProductReturnType which transforms it to (col col *) by evaluating rhs. - -} // end namespace internal - -// sparse = sparse * sparse -template -template -inline Derived& SparseMatrixBase::operator=(const SparseSparseProduct& product) -{ -// std::cerr << "there..." << typeid(Lhs).name() << " " << typeid(Lhs).name() << " " << (Derived::Flags&&RowMajorBit) << "\n"; - internal::sparse_product_selector< - typename internal::remove_all::type, - typename internal::remove_all::type, - Derived>::run(product.lhs(),product.rhs(),derived()); - return derived(); -} - -namespace internal { - -template::Flags&RowMajorBit, - int RhsStorageOrder = traits::Flags&RowMajorBit, - int ResStorageOrder = traits::Flags&RowMajorBit> -struct sparse_product_selector2; - -template -struct sparse_product_selector2 -{ - typedef typename traits::type>::Scalar Scalar; - - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { - sparse_product_impl2(lhs, rhs, res); - } -}; - -template -struct sparse_product_selector2 -{ - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { - // prevent warnings until the code is fixed - EIGEN_UNUSED_VARIABLE(lhs); - EIGEN_UNUSED_VARIABLE(rhs); - EIGEN_UNUSED_VARIABLE(res); - -// typedef SparseMatrix RowMajorMatrix; -// RowMajorMatrix rhsRow = rhs; -// RowMajorMatrix resRow(res.rows(), res.cols()); -// sparse_product_impl2(rhsRow, lhs, resRow); -// res = resRow; - } -}; - -template -struct sparse_product_selector2 -{ - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { - typedef SparseMatrix RowMajorMatrix; - RowMajorMatrix lhsRow = lhs; - RowMajorMatrix resRow(res.rows(), res.cols()); - sparse_product_impl2(rhs, lhsRow, resRow); - res = resRow; - } -}; - -template -struct sparse_product_selector2 -{ - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { - typedef SparseMatrix RowMajorMatrix; - RowMajorMatrix resRow(res.rows(), res.cols()); - sparse_product_impl2(rhs, lhs, resRow); - res = resRow; - } -}; - - -template -struct sparse_product_selector2 -{ - typedef typename traits::type>::Scalar Scalar; - - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { - typedef SparseMatrix ColMajorMatrix; - ColMajorMatrix resCol(res.rows(), res.cols()); - sparse_product_impl2(lhs, rhs, resCol); - res = resCol; - } -}; - -template -struct sparse_product_selector2 -{ - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { - typedef SparseMatrix ColMajorMatrix; - ColMajorMatrix lhsCol = lhs; - ColMajorMatrix resCol(res.rows(), res.cols()); - sparse_product_impl2(lhsCol, rhs, resCol); - res = resCol; - } -}; - -template -struct sparse_product_selector2 -{ - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { - typedef SparseMatrix ColMajorMatrix; - ColMajorMatrix rhsCol = rhs; - ColMajorMatrix resCol(res.rows(), res.cols()); - sparse_product_impl2(lhs, rhsCol, resCol); - res = resCol; - } -}; - -template -struct sparse_product_selector2 -{ - static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) - { - typedef SparseMatrix ColMajorMatrix; -// ColMajorMatrix lhsTr(lhs); -// ColMajorMatrix rhsTr(rhs); -// ColMajorMatrix aux(res.rows(), res.cols()); -// sparse_product_impl2(rhs, lhs, aux); -// // ColMajorMatrix aux2 = aux.transpose(); -// res = aux; - typedef SparseMatrix ColMajorMatrix; - ColMajorMatrix lhsCol(lhs); - ColMajorMatrix rhsCol(rhs); - ColMajorMatrix resCol(res.rows(), res.cols()); - sparse_product_impl2(lhsCol, rhsCol, resCol); - res = resCol; - } -}; - -} // end namespace internal - -template -template -inline void SparseMatrixBase::_experimentalNewProduct(const Lhs& lhs, const Rhs& rhs) -{ - //derived().resize(lhs.rows(), rhs.cols()); - internal::sparse_product_selector2< - typename internal::remove_all::type, - typename internal::remove_all::type, - Derived>::run(lhs,rhs,derived()); -} - -// sparse * sparse -template -template -inline const typename SparseSparseProductReturnType::Type -SparseMatrixBase::operator*(const SparseMatrixBase &other) const -{ - return typename SparseSparseProductReturnType::Type(derived(), other.derived()); -} - -#endif // EIGEN_SPARSESPARSEPRODUCT_H diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseTranspose.h b/extern/Eigen3/Eigen/src/Sparse/SparseTranspose.h deleted file mode 100644 index 2aea2fa32c7..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/SparseTranspose.h +++ /dev/null @@ -1,68 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSETRANSPOSE_H -#define EIGEN_SPARSETRANSPOSE_H - -template class TransposeImpl - : public SparseMatrixBase > -{ - typedef typename internal::remove_all::type _MatrixTypeNested; - public: - - EIGEN_SPARSE_PUBLIC_INTERFACE(Transpose) - - class InnerIterator; - class ReverseInnerIterator; - - inline Index nonZeros() const { return derived().nestedExpression().nonZeros(); } -}; - -template class TransposeImpl::InnerIterator - : public _MatrixTypeNested::InnerIterator -{ - typedef typename _MatrixTypeNested::InnerIterator Base; - public: - - EIGEN_STRONG_INLINE InnerIterator(const TransposeImpl& trans, Index outer) - : Base(trans.derived().nestedExpression(), outer) - {} - inline Index row() const { return Base::col(); } - inline Index col() const { return Base::row(); } -}; - -template class TransposeImpl::ReverseInnerIterator - : public _MatrixTypeNested::ReverseInnerIterator -{ - typedef typename _MatrixTypeNested::ReverseInnerIterator Base; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const TransposeImpl& xpr, Index outer) - : Base(xpr.derived().nestedExpression(), outer) - {} - inline Index row() const { return Base::col(); } - inline Index col() const { return Base::row(); } -}; - -#endif // EIGEN_SPARSETRANSPOSE_H diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseTriangularView.h b/extern/Eigen3/Eigen/src/Sparse/SparseTriangularView.h deleted file mode 100644 index 319eaf06638..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/SparseTriangularView.h +++ /dev/null @@ -1,100 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSE_TRIANGULARVIEW_H -#define EIGEN_SPARSE_TRIANGULARVIEW_H - -namespace internal { - -template -struct traits > -: public traits -{}; - -} // namespace internal - -template class SparseTriangularView - : public SparseMatrixBase > -{ - enum { SkipFirst = (Mode==Lower && !(MatrixType::Flags&RowMajorBit)) - || (Mode==Upper && (MatrixType::Flags&RowMajorBit)) }; - public: - - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseTriangularView) - - class InnerIterator; - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - - typedef typename internal::conditional::ret, - MatrixType, const MatrixType&>::type MatrixTypeNested; - - inline SparseTriangularView(const MatrixType& matrix) : m_matrix(matrix) {} - - /** \internal */ - inline const MatrixType& nestedExpression() const { return m_matrix; } - - template - typename internal::plain_matrix_type_column_major::type - solve(const MatrixBase& other) const; - - template void solveInPlace(MatrixBase& other) const; - template void solveInPlace(SparseMatrixBase& other) const; - - protected: - MatrixTypeNested m_matrix; -}; - -template -class SparseTriangularView::InnerIterator : public MatrixType::InnerIterator -{ - typedef typename MatrixType::InnerIterator Base; - public: - - EIGEN_STRONG_INLINE InnerIterator(const SparseTriangularView& view, Index outer) - : Base(view.nestedExpression(), outer) - { - if(SkipFirst) - while((*this) && this->index()index() <= this->outer()); - } -}; - -template -template -inline const SparseTriangularView -SparseMatrixBase::triangularView() const -{ - return derived(); -} - -#endif // EIGEN_SPARSE_TRIANGULARVIEW_H diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseUtil.h b/extern/Eigen3/Eigen/src/Sparse/SparseUtil.h deleted file mode 100644 index db9ae98e7a0..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/SparseUtil.h +++ /dev/null @@ -1,130 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSEUTIL_H -#define EIGEN_SPARSEUTIL_H - -#ifdef NDEBUG -#define EIGEN_DBG_SPARSE(X) -#else -#define EIGEN_DBG_SPARSE(X) X -#endif - -#define EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, Op) \ -template \ -EIGEN_STRONG_INLINE Derived& operator Op(const Eigen::SparseMatrixBase& other) \ -{ \ - return Base::operator Op(other.derived()); \ -} \ -EIGEN_STRONG_INLINE Derived& operator Op(const Derived& other) \ -{ \ - return Base::operator Op(other); \ -} - -#define EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, Op) \ -template \ -EIGEN_STRONG_INLINE Derived& operator Op(const Other& scalar) \ -{ \ - return Base::operator Op(scalar); \ -} - -#define EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATORS(Derived) \ -EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, =) \ -EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, +=) \ -EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, -=) \ -EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, *=) \ -EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, /=) - -#define _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, BaseClass) \ - typedef BaseClass Base; \ - typedef typename Eigen::internal::traits::Scalar Scalar; \ - typedef typename Eigen::NumTraits::Real RealScalar; \ - typedef typename Eigen::internal::nested::type Nested; \ - typedef typename Eigen::internal::traits::StorageKind StorageKind; \ - typedef typename Eigen::internal::traits::Index Index; \ - enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ - ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ - Flags = Eigen::internal::traits::Flags, \ - CoeffReadCost = Eigen::internal::traits::CoeffReadCost, \ - SizeAtCompileTime = Base::SizeAtCompileTime, \ - IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; \ - using Base::derived; \ - using Base::const_cast_derived; - -#define EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) \ - _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, Eigen::SparseMatrixBase) - -const int CoherentAccessPattern = 0x1; -const int InnerRandomAccessPattern = 0x2 | CoherentAccessPattern; -const int OuterRandomAccessPattern = 0x4 | CoherentAccessPattern; -const int RandomAccessPattern = 0x8 | OuterRandomAccessPattern | InnerRandomAccessPattern; - -template class SparseMatrixBase; -template class SparseMatrix; -template class DynamicSparseMatrix; -template class SparseVector; -template class MappedSparseMatrix; - -template class SparseInnerVectorSet; -template class SparseTriangularView; -template class SparseSelfAdjointView; -template class SparseDiagonalProduct; -template class SparseView; - -template class SparseSparseProduct; -template class SparseTimeDenseProduct; -template class DenseTimeSparseProduct; -template class SparseDenseOuterProduct; - -template struct SparseSparseProductReturnType; -template::ColsAtCompileTime> struct DenseSparseProductReturnType; -template::ColsAtCompileTime> struct SparseDenseProductReturnType; - -namespace internal { - -template struct eval -{ - typedef typename traits::Scalar _Scalar; - enum { - _Flags = traits::Flags - }; - - public: - typedef SparseMatrix<_Scalar, _Flags> type; -}; - -template struct plain_matrix_type -{ - typedef typename traits::Scalar _Scalar; - enum { - _Flags = traits::Flags - }; - - public: - typedef SparseMatrix<_Scalar, _Flags> type; -}; - -} // end namespace internal - -#endif // EIGEN_SPARSEUTIL_H diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseVector.h b/extern/Eigen3/Eigen/src/Sparse/SparseVector.h deleted file mode 100644 index ce4bb51a27e..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/SparseVector.h +++ /dev/null @@ -1,431 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSEVECTOR_H -#define EIGEN_SPARSEVECTOR_H - -/** \class SparseVector - * - * \brief a sparse vector class - * - * \tparam _Scalar the scalar type, i.e. the type of the coefficients - * - * See http://www.netlib.org/linalg/html_templates/node91.html for details on the storage scheme. - * - * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEVECTOR_PLUGIN. - */ - -namespace internal { -template -struct traits > -{ - typedef _Scalar Scalar; - typedef _Index Index; - typedef Sparse StorageKind; - typedef MatrixXpr XprKind; - enum { - IsColVector = _Options & RowMajorBit ? 0 : 1, - - RowsAtCompileTime = IsColVector ? Dynamic : 1, - ColsAtCompileTime = IsColVector ? 1 : Dynamic, - MaxRowsAtCompileTime = RowsAtCompileTime, - MaxColsAtCompileTime = ColsAtCompileTime, - Flags = _Options | NestByRefBit | LvalueBit, - CoeffReadCost = NumTraits::ReadCost, - SupportedAccessPatterns = InnerRandomAccessPattern - }; -}; -} - -template -class SparseVector - : public SparseMatrixBase > -{ - public: - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseVector) - EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, +=) - EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, -=) -// EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, =) - - protected: - public: - - typedef SparseMatrixBase SparseBase; - enum { IsColVector = internal::traits::IsColVector }; - - enum { - Options = _Options - }; - - CompressedStorage m_data; - Index m_size; - - CompressedStorage& _data() { return m_data; } - CompressedStorage& _data() const { return m_data; } - - public: - - EIGEN_STRONG_INLINE Index rows() const { return IsColVector ? m_size : 1; } - EIGEN_STRONG_INLINE Index cols() const { return IsColVector ? 1 : m_size; } - EIGEN_STRONG_INLINE Index innerSize() const { return m_size; } - EIGEN_STRONG_INLINE Index outerSize() const { return 1; } - EIGEN_STRONG_INLINE Index innerNonZeros(Index j) const { eigen_assert(j==0); return m_size; } - - EIGEN_STRONG_INLINE const Scalar* _valuePtr() const { return &m_data.value(0); } - EIGEN_STRONG_INLINE Scalar* _valuePtr() { return &m_data.value(0); } - - EIGEN_STRONG_INLINE const Index* _innerIndexPtr() const { return &m_data.index(0); } - EIGEN_STRONG_INLINE Index* _innerIndexPtr() { return &m_data.index(0); } - - inline Scalar coeff(Index row, Index col) const - { - eigen_assert((IsColVector ? col : row)==0); - return coeff(IsColVector ? row : col); - } - inline Scalar coeff(Index i) const { return m_data.at(i); } - - inline Scalar& coeffRef(Index row, Index col) - { - eigen_assert((IsColVector ? col : row)==0); - return coeff(IsColVector ? row : col); - } - - /** \returns a reference to the coefficient value at given index \a i - * This operation involes a log(rho*size) binary search. If the coefficient does not - * exist yet, then a sorted insertion into a sequential buffer is performed. - * - * This insertion might be very costly if the number of nonzeros above \a i is large. - */ - inline Scalar& coeffRef(Index i) - { - return m_data.atWithInsertion(i); - } - - public: - - class InnerIterator; - - inline void setZero() { m_data.clear(); } - - /** \returns the number of non zero coefficients */ - inline Index nonZeros() const { return static_cast(m_data.size()); } - - inline void startVec(Index outer) - { - eigen_assert(outer==0); - } - - inline Scalar& insertBackByOuterInner(Index outer, Index inner) - { - eigen_assert(outer==0); - return insertBack(inner); - } - inline Scalar& insertBack(Index i) - { - m_data.append(0, i); - return m_data.value(m_data.size()-1); - } - - inline Scalar& insert(Index row, Index col) - { - Index inner = IsColVector ? row : col; - Index outer = IsColVector ? col : row; - eigen_assert(outer==0); - return insert(inner); - } - Scalar& insert(Index i) - { - Index startId = 0; - Index p = m_data.size() - 1; - // TODO smart realloc - m_data.resize(p+2,1); - - while ( (p >= startId) && (m_data.index(p) > i) ) - { - m_data.index(p+1) = m_data.index(p); - m_data.value(p+1) = m_data.value(p); - --p; - } - m_data.index(p+1) = i; - m_data.value(p+1) = 0; - return m_data.value(p+1); - } - - /** - */ - inline void reserve(Index reserveSize) { m_data.reserve(reserveSize); } - - - inline void finalize() {} - - void prune(Scalar reference, RealScalar epsilon = NumTraits::dummy_precision()) - { - m_data.prune(reference,epsilon); - } - - void resize(Index rows, Index cols) - { - eigen_assert(rows==1 || cols==1); - resize(IsColVector ? rows : cols); - } - - void resize(Index newSize) - { - m_size = newSize; - m_data.clear(); - } - - void resizeNonZeros(Index size) { m_data.resize(size); } - - inline SparseVector() : m_size(0) { resize(0); } - - inline SparseVector(Index size) : m_size(0) { resize(size); } - - inline SparseVector(Index rows, Index cols) : m_size(0) { resize(rows,cols); } - - template - inline SparseVector(const MatrixBase& other) - : m_size(0) - { - *this = other.derived(); - } - - template - inline SparseVector(const SparseMatrixBase& other) - : m_size(0) - { - *this = other.derived(); - } - - inline SparseVector(const SparseVector& other) - : m_size(0) - { - *this = other.derived(); - } - - inline void swap(SparseVector& other) - { - std::swap(m_size, other.m_size); - m_data.swap(other.m_data); - } - - inline SparseVector& operator=(const SparseVector& other) - { - if (other.isRValue()) - { - swap(other.const_cast_derived()); - } - else - { - resize(other.size()); - m_data = other.m_data; - } - return *this; - } - - template - inline SparseVector& operator=(const SparseMatrixBase& other) - { - if (int(RowsAtCompileTime)!=int(OtherDerived::RowsAtCompileTime)) - return Base::operator=(other.transpose()); - else - return Base::operator=(other); - } - - #ifndef EIGEN_PARSED_BY_DOXYGEN - template - inline SparseVector& operator=(const SparseSparseProduct& product) - { - return Base::operator=(product); - } - #endif - -// const bool needToTranspose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); -// if (needToTranspose) -// { -// // two passes algorithm: -// // 1 - compute the number of coeffs per dest inner vector -// // 2 - do the actual copy/eval -// // Since each coeff of the rhs has to be evaluated twice, let's evauluate it if needed -// typedef typename internal::nested::type OtherCopy; -// OtherCopy otherCopy(other.derived()); -// typedef typename internal::remove_all::type _OtherCopy; -// -// resize(other.rows(), other.cols()); -// Eigen::Map(m_outerIndex,outerSize()).setZero(); -// // pass 1 -// // FIXME the above copy could be merged with that pass -// for (int j=0; j::operator=(other.derived()); -// } -// } - - friend std::ostream & operator << (std::ostream & s, const SparseVector& m) - { - for (Index i=0; i -class SparseVector::InnerIterator -{ - public: - InnerIterator(const SparseVector& vec, Index outer=0) - : m_data(vec.m_data), m_id(0), m_end(static_cast(m_data.size())) - { - eigen_assert(outer==0); - } - - InnerIterator(const CompressedStorage& data) - : m_data(data), m_id(0), m_end(static_cast(m_data.size())) - {} - - template - InnerIterator(const Flagged& vec, Index ) - : m_data(vec._expression().m_data), m_id(0), m_end(m_data.size()) - {} - - inline InnerIterator& operator++() { m_id++; return *this; } - - inline Scalar value() const { return m_data.value(m_id); } - inline Scalar& valueRef() { return const_cast(m_data.value(m_id)); } - - inline Index index() const { return m_data.index(m_id); } - inline Index row() const { return IsColVector ? index() : 0; } - inline Index col() const { return IsColVector ? 0 : index(); } - - inline operator bool() const { return (m_id < m_end); } - - protected: - const CompressedStorage& m_data; - Index m_id; - const Index m_end; -}; - -#endif // EIGEN_SPARSEVECTOR_H diff --git a/extern/Eigen3/Eigen/src/Sparse/SparseView.h b/extern/Eigen3/Eigen/src/Sparse/SparseView.h deleted file mode 100644 index 24306561098..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/SparseView.h +++ /dev/null @@ -1,109 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2010 Gael Guennebaud -// Copyright (C) 2010 Daniel Lowengrub -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSEVIEW_H -#define EIGEN_SPARSEVIEW_H - -namespace internal { - -template -struct traits > : traits -{ - typedef int Index; - typedef Sparse StorageKind; - enum { - Flags = int(traits::Flags) & (RowMajorBit) - }; -}; - -} // end namespace internal - -template -class SparseView : public SparseMatrixBase > -{ - typedef typename MatrixType::Nested MatrixTypeNested; - typedef typename internal::remove_all::type _MatrixTypeNested; -public: - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseView) - - SparseView(const MatrixType& mat, const Scalar& m_reference = Scalar(0), - typename NumTraits::Real m_epsilon = NumTraits::dummy_precision()) : - m_matrix(mat), m_reference(m_reference), m_epsilon(m_epsilon) {} - - class InnerIterator; - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - - inline Index innerSize() const { return m_matrix.innerSize(); } - inline Index outerSize() const { return m_matrix.outerSize(); } - -protected: - const MatrixTypeNested m_matrix; - Scalar m_reference; - typename NumTraits::Real m_epsilon; -}; - -template -class SparseView::InnerIterator : public _MatrixTypeNested::InnerIterator -{ -public: - typedef typename _MatrixTypeNested::InnerIterator IterBase; - InnerIterator(const SparseView& view, Index outer) : - IterBase(view.m_matrix, outer), m_view(view) - { - incrementToNonZero(); - } - - EIGEN_STRONG_INLINE InnerIterator& operator++() - { - IterBase::operator++(); - incrementToNonZero(); - return *this; - } - - using IterBase::value; - -protected: - const SparseView& m_view; - -private: - void incrementToNonZero() - { - while(internal::isMuchSmallerThan(value(), m_view.m_reference, m_view.m_epsilon) && (bool(*this))) - { - IterBase::operator++(); - } - } -}; - -template -const SparseView MatrixBase::sparseView(const Scalar& m_reference, - typename NumTraits::Real m_epsilon) const -{ - return SparseView(derived(), m_reference, m_epsilon); -} - -#endif diff --git a/extern/Eigen3/Eigen/src/Sparse/TriangularSolver.h b/extern/Eigen3/Eigen/src/Sparse/TriangularSolver.h deleted file mode 100644 index 62bb8bb44c9..00000000000 --- a/extern/Eigen3/Eigen/src/Sparse/TriangularSolver.h +++ /dev/null @@ -1,339 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSETRIANGULARSOLVER_H -#define EIGEN_SPARSETRIANGULARSOLVER_H - -namespace internal { - -template::Flags) & RowMajorBit> -struct sparse_solve_triangular_selector; - -// forward substitution, row-major -template -struct sparse_solve_triangular_selector -{ - typedef typename Rhs::Scalar Scalar; - static void run(const Lhs& lhs, Rhs& other) - { - for(int col=0 ; col -struct sparse_solve_triangular_selector -{ - typedef typename Rhs::Scalar Scalar; - static void run(const Lhs& lhs, Rhs& other) - { - for(int col=0 ; col=0 ; --i) - { - Scalar tmp = other.coeff(i,col); - typename Lhs::InnerIterator it(lhs, i); - if (it && it.index() == i) - ++it; - for(; it; ++it) - { - tmp -= it.value() * other.coeff(it.index(),col); - } - - if (Mode & UnitDiag) - other.coeffRef(i,col) = tmp; - else - { - typename Lhs::InnerIterator it(lhs, i); - eigen_assert(it && it.index() == i); - other.coeffRef(i,col) = tmp/it.value(); - } - } - } - } -}; - -// forward substitution, col-major -template -struct sparse_solve_triangular_selector -{ - typedef typename Rhs::Scalar Scalar; - static void run(const Lhs& lhs, Rhs& other) - { - for(int col=0 ; col -struct sparse_solve_triangular_selector -{ - typedef typename Rhs::Scalar Scalar; - static void run(const Lhs& lhs, Rhs& other) - { - for(int col=0 ; col=0; --i) - { - Scalar& tmp = other.coeffRef(i,col); - if (tmp!=Scalar(0)) // optimization when other is actually sparse - { - if(!(Mode & UnitDiag)) - { - // FIXME lhs.coeff(i,i) might not be always efficient while it must simply be the - // last element of the column ! - other.coeffRef(i,col) /= lhs.innerVector(i).lastCoeff(); - } - typename Lhs::InnerIterator it(lhs, i); - for(; it && it.index() -template -void SparseTriangularView::solveInPlace(MatrixBase& other) const -{ - eigen_assert(m_matrix.cols() == m_matrix.rows()); - eigen_assert(m_matrix.cols() == other.rows()); - eigen_assert(!(Mode & ZeroDiag)); - eigen_assert((Mode & (Upper|Lower)) != 0); - - enum { copy = internal::traits::Flags & RowMajorBit }; - - typedef typename internal::conditional::type, OtherDerived&>::type OtherCopy; - OtherCopy otherCopy(other.derived()); - - internal::sparse_solve_triangular_selector::type, Mode>::run(m_matrix, otherCopy); - - if (copy) - other = otherCopy; -} - -template -template -typename internal::plain_matrix_type_column_major::type -SparseTriangularView::solve(const MatrixBase& other) const -{ - typename internal::plain_matrix_type_column_major::type res(other); - solveInPlace(res); - return res; -} - -// pure sparse path - -namespace internal { - -template -struct sparse_solve_triangular_sparse_selector; - -// forward substitution, col-major -template -struct sparse_solve_triangular_sparse_selector -{ - typedef typename Rhs::Scalar Scalar; - typedef typename promote_index_type::Index, - typename traits::Index>::type Index; - static void run(const Lhs& lhs, Rhs& other) - { - const bool IsLower = (UpLo==Lower); - AmbiVector tempVector(other.rows()*2); - tempVector.setBounds(0,other.rows()); - - Rhs res(other.rows(), other.cols()); - res.reserve(other.nonZeros()); - - for(int col=0 ; col=0; - i+=IsLower?1:-1) - { - tempVector.restart(); - Scalar& ci = tempVector.coeffRef(i); - if (ci!=Scalar(0)) - { - // find - typename Lhs::InnerIterator it(lhs, i); - if(!(Mode & UnitDiag)) - { - if (IsLower) - { - eigen_assert(it.index()==i); - ci /= it.value(); - } - else - ci /= lhs.coeff(i,i); - } - tempVector.restart(); - if (IsLower) - { - if (it.index()==i) - ++it; - for(; it; ++it) - tempVector.coeffRef(it.index()) -= ci * it.value(); - } - else - { - for(; it && it.index()::Iterator it(tempVector/*,1e-12*/); it; ++it) - { - ++ count; -// std::cerr << "fill " << it.index() << ", " << col << "\n"; -// std::cout << it.value() << " "; - // FIXME use insertBack - res.insert(it.index(), col) = it.value(); - } -// std::cout << "tempVector.nonZeros() == " << int(count) << " / " << (other.rows()) << "\n"; - } - res.finalize(); - other = res.markAsRValue(); - } -}; - -} // end namespace internal - -template -template -void SparseTriangularView::solveInPlace(SparseMatrixBase& other) const -{ - eigen_assert(m_matrix.cols() == m_matrix.rows()); - eigen_assert(m_matrix.cols() == other.rows()); - eigen_assert(!(Mode & ZeroDiag)); - eigen_assert((Mode & (Upper|Lower)) != 0); - -// enum { copy = internal::traits::Flags & RowMajorBit }; - -// typedef typename internal::conditional::type, OtherDerived&>::type OtherCopy; -// OtherCopy otherCopy(other.derived()); - - internal::sparse_solve_triangular_sparse_selector::run(m_matrix, other.derived()); - -// if (copy) -// other = otherCopy; -} - -#ifdef EIGEN2_SUPPORT - -// deprecated stuff: - -/** \deprecated */ -template -template -void SparseMatrixBase::solveTriangularInPlace(MatrixBase& other) const -{ - this->template triangular().solveInPlace(other); -} - -/** \deprecated */ -template -template -typename internal::plain_matrix_type_column_major::type -SparseMatrixBase::solveTriangular(const MatrixBase& other) const -{ - typename internal::plain_matrix_type_column_major::type res(other); - derived().solveTriangularInPlace(res); - return res; -} -#endif // EIGEN2_SUPPORT - -#endif // EIGEN_SPARSETRIANGULARSOLVER_H diff --git a/extern/Eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h b/extern/Eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h new file mode 100644 index 00000000000..9bf38ab2d91 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h @@ -0,0 +1,873 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/* + +NOTE: the _symbolic, and _numeric functions has been adapted from + the LDL library: + +LDL Copyright (c) 2005 by Timothy A. Davis. All Rights Reserved. + +LDL License: + + Your use or distribution of LDL or any modified version of + LDL implies that you agree to this License. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA + + Permission is hereby granted to use or copy this program under the + terms of the GNU LGPL, provided that the Copyright, this License, + and the Availability of the original version is retained on all copies. + User documentation of any code that uses this code or any modified + version of this code must cite the Copyright, this License, the + Availability note, and "Used by permission." Permission to modify + the code and to distribute modified code is granted, provided the + Copyright, this License, and the Availability note are retained, + and a notice that the code was modified is included. + */ + +#include "../Core/util/NonMPL2.h" + +#ifndef EIGEN_SIMPLICIAL_CHOLESKY_H +#define EIGEN_SIMPLICIAL_CHOLESKY_H + +namespace Eigen { + +enum SimplicialCholeskyMode { + SimplicialCholeskyLLT, + SimplicialCholeskyLDLT +}; + +/** \ingroup SparseCholesky_Module + * \brief A direct sparse Cholesky factorizations + * + * These classes provide LL^T and LDL^T Cholesky factorizations of sparse matrices that are + * selfadjoint and positive definite. The factorization allows for solving A.X = B where + * X and B can be either dense or sparse. + * + * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization + * such that the factorized matrix is P A P^-1. + * + * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower + * or Upper. Default is Lower. + * + */ +template +class SimplicialCholeskyBase : internal::noncopyable +{ + public: + typedef typename internal::traits::MatrixType MatrixType; + enum { UpLo = internal::traits::UpLo }; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + typedef SparseMatrix CholMatrixType; + typedef Matrix VectorType; + + public: + + /** Default constructor */ + SimplicialCholeskyBase() + : m_info(Success), m_isInitialized(false), m_shiftOffset(0), m_shiftScale(1) + {} + + SimplicialCholeskyBase(const MatrixType& matrix) + : m_info(Success), m_isInitialized(false), m_shiftOffset(0), m_shiftScale(1) + { + derived().compute(matrix); + } + + ~SimplicialCholeskyBase() + { + } + + Derived& derived() { return *static_cast(this); } + const Derived& derived() const { return *static_cast(this); } + + inline Index cols() const { return m_matrix.cols(); } + inline Index rows() const { return m_matrix.rows(); } + + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was succesful, + * \c NumericalIssue if the matrix.appears to be negative. + */ + ComputationInfo info() const + { + eigen_assert(m_isInitialized && "Decomposition is not initialized."); + return m_info; + } + + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ + template + inline const internal::solve_retval + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "Simplicial LLT or LDLT is not initialized."); + eigen_assert(rows()==b.rows() + && "SimplicialCholeskyBase::solve(): invalid number of rows of the right hand side matrix b"); + return internal::solve_retval(*this, b.derived()); + } + + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ + template + inline const internal::sparse_solve_retval + solve(const SparseMatrixBase& b) const + { + eigen_assert(m_isInitialized && "Simplicial LLT or LDLT is not initialized."); + eigen_assert(rows()==b.rows() + && "SimplicialCholesky::solve(): invalid number of rows of the right hand side matrix b"); + return internal::sparse_solve_retval(*this, b.derived()); + } + + /** \returns the permutation P + * \sa permutationPinv() */ + const PermutationMatrix& permutationP() const + { return m_P; } + + /** \returns the inverse P^-1 of the permutation P + * \sa permutationP() */ + const PermutationMatrix& permutationPinv() const + { return m_Pinv; } + + /** Sets the shift parameters that will be used to adjust the diagonal coefficients during the numerical factorization. + * + * During the numerical factorization, the diagonal coefficients are transformed by the following linear model:\n + * \c d_ii = \a offset + \a scale * \c d_ii + * + * The default is the identity transformation with \a offset=0, and \a scale=1. + * + * \returns a reference to \c *this. + */ + Derived& setShift(const RealScalar& offset, const RealScalar& scale = 1) + { + m_shiftOffset = offset; + m_shiftScale = scale; + return derived(); + } + +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal */ + template + void dumpMemory(Stream& s) + { + int total = 0; + s << " L: " << ((total+=(m_matrix.cols()+1) * sizeof(int) + m_matrix.nonZeros()*(sizeof(int)+sizeof(Scalar))) >> 20) << "Mb" << "\n"; + s << " diag: " << ((total+=m_diag.size() * sizeof(Scalar)) >> 20) << "Mb" << "\n"; + s << " tree: " << ((total+=m_parent.size() * sizeof(int)) >> 20) << "Mb" << "\n"; + s << " nonzeros: " << ((total+=m_nonZerosPerCol.size() * sizeof(int)) >> 20) << "Mb" << "\n"; + s << " perm: " << ((total+=m_P.size() * sizeof(int)) >> 20) << "Mb" << "\n"; + s << " perm^-1: " << ((total+=m_Pinv.size() * sizeof(int)) >> 20) << "Mb" << "\n"; + s << " TOTAL: " << (total>> 20) << "Mb" << "\n"; + } + + /** \internal */ + template + void _solve(const MatrixBase &b, MatrixBase &dest) const + { + eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); + eigen_assert(m_matrix.rows()==b.rows()); + + if(m_info!=Success) + return; + + if(m_P.size()>0) + dest = m_P * b; + else + dest = b; + + if(m_matrix.nonZeros()>0) // otherwise L==I + derived().matrixL().solveInPlace(dest); + + if(m_diag.size()>0) + dest = m_diag.asDiagonal().inverse() * dest; + + if (m_matrix.nonZeros()>0) // otherwise U==I + derived().matrixU().solveInPlace(dest); + + if(m_P.size()>0) + dest = m_Pinv * dest; + } + + /** \internal */ + template + void _solve_sparse(const Rhs& b, SparseMatrix &dest) const + { + eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); + eigen_assert(m_matrix.rows()==b.rows()); + + // we process the sparse rhs per block of NbColsAtOnce columns temporarily stored into a dense matrix. + static const int NbColsAtOnce = 4; + int rhsCols = b.cols(); + int size = b.rows(); + Eigen::Matrix tmp(size,rhsCols); + for(int k=0; k(rhsCols-k, NbColsAtOnce); + tmp.leftCols(actualCols) = b.middleCols(k,actualCols); + tmp.leftCols(actualCols) = derived().solve(tmp.leftCols(actualCols)); + dest.middleCols(k,actualCols) = tmp.leftCols(actualCols).sparseView(); + } + } + +#endif // EIGEN_PARSED_BY_DOXYGEN + + protected: + + /** Computes the sparse Cholesky decomposition of \a matrix */ + template + void compute(const MatrixType& matrix) + { + eigen_assert(matrix.rows()==matrix.cols()); + Index size = matrix.cols(); + CholMatrixType ap(size,size); + ordering(matrix, ap); + analyzePattern_preordered(ap, DoLDLT); + factorize_preordered(ap); + } + + template + void factorize(const MatrixType& a) + { + eigen_assert(a.rows()==a.cols()); + int size = a.cols(); + CholMatrixType ap(size,size); + ap.template selfadjointView() = a.template selfadjointView().twistedBy(m_P); + factorize_preordered(ap); + } + + template + void factorize_preordered(const CholMatrixType& a); + + void analyzePattern(const MatrixType& a, bool doLDLT) + { + eigen_assert(a.rows()==a.cols()); + int size = a.cols(); + CholMatrixType ap(size,size); + ordering(a, ap); + analyzePattern_preordered(ap,doLDLT); + } + void analyzePattern_preordered(const CholMatrixType& a, bool doLDLT); + + void ordering(const MatrixType& a, CholMatrixType& ap); + + /** keeps off-diagonal entries; drops diagonal entries */ + struct keep_diag { + inline bool operator() (const Index& row, const Index& col, const Scalar&) const + { + return row!=col; + } + }; + + mutable ComputationInfo m_info; + bool m_isInitialized; + bool m_factorizationIsOk; + bool m_analysisIsOk; + + CholMatrixType m_matrix; + VectorType m_diag; // the diagonal coefficients (LDLT mode) + VectorXi m_parent; // elimination tree + VectorXi m_nonZerosPerCol; + PermutationMatrix m_P; // the permutation + PermutationMatrix m_Pinv; // the inverse permutation + + RealScalar m_shiftOffset; + RealScalar m_shiftScale; +}; + +template class SimplicialLLT; +template class SimplicialLDLT; +template class SimplicialCholesky; + +namespace internal { + +template struct traits > +{ + typedef _MatrixType MatrixType; + enum { UpLo = _UpLo }; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::Index Index; + typedef SparseMatrix CholMatrixType; + typedef SparseTriangularView MatrixL; + typedef SparseTriangularView MatrixU; + static inline MatrixL getL(const MatrixType& m) { return m; } + static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } +}; + +template struct traits > +{ + typedef _MatrixType MatrixType; + enum { UpLo = _UpLo }; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::Index Index; + typedef SparseMatrix CholMatrixType; + typedef SparseTriangularView MatrixL; + typedef SparseTriangularView MatrixU; + static inline MatrixL getL(const MatrixType& m) { return m; } + static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } +}; + +template struct traits > +{ + typedef _MatrixType MatrixType; + enum { UpLo = _UpLo }; +}; + +} + +/** \ingroup SparseCholesky_Module + * \class SimplicialLLT + * \brief A direct sparse LLT Cholesky factorizations + * + * This class provides a LL^T Cholesky factorizations of sparse matrices that are + * selfadjoint and positive definite. The factorization allows for solving A.X = B where + * X and B can be either dense or sparse. + * + * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization + * such that the factorized matrix is P A P^-1. + * + * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower + * or Upper. Default is Lower. + * + * \sa class SimplicialLDLT + */ +template + class SimplicialLLT : public SimplicialCholeskyBase > +{ +public: + typedef _MatrixType MatrixType; + enum { UpLo = _UpLo }; + typedef SimplicialCholeskyBase Base; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + typedef SparseMatrix CholMatrixType; + typedef Matrix VectorType; + typedef internal::traits Traits; + typedef typename Traits::MatrixL MatrixL; + typedef typename Traits::MatrixU MatrixU; +public: + /** Default constructor */ + SimplicialLLT() : Base() {} + /** Constructs and performs the LLT factorization of \a matrix */ + SimplicialLLT(const MatrixType& matrix) + : Base(matrix) {} + + /** \returns an expression of the factor L */ + inline const MatrixL matrixL() const { + eigen_assert(Base::m_factorizationIsOk && "Simplicial LLT not factorized"); + return Traits::getL(Base::m_matrix); + } + + /** \returns an expression of the factor U (= L^*) */ + inline const MatrixU matrixU() const { + eigen_assert(Base::m_factorizationIsOk && "Simplicial LLT not factorized"); + return Traits::getU(Base::m_matrix); + } + + /** Computes the sparse Cholesky decomposition of \a matrix */ + SimplicialLLT& compute(const MatrixType& matrix) + { + Base::template compute(matrix); + return *this; + } + + /** Performs a symbolic decomposition on the sparcity of \a matrix. + * + * This function is particularly useful when solving for several problems having the same structure. + * + * \sa factorize() + */ + void analyzePattern(const MatrixType& a) + { + Base::analyzePattern(a, false); + } + + /** Performs a numeric decomposition of \a matrix + * + * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. + * + * \sa analyzePattern() + */ + void factorize(const MatrixType& a) + { + Base::template factorize(a); + } + + /** \returns the determinant of the underlying matrix from the current factorization */ + Scalar determinant() const + { + Scalar detL = Base::m_matrix.diagonal().prod(); + return internal::abs2(detL); + } +}; + +/** \ingroup SparseCholesky_Module + * \class SimplicialLDLT + * \brief A direct sparse LDLT Cholesky factorizations without square root. + * + * This class provides a LDL^T Cholesky factorizations without square root of sparse matrices that are + * selfadjoint and positive definite. The factorization allows for solving A.X = B where + * X and B can be either dense or sparse. + * + * In order to reduce the fill-in, a symmetric permutation P is applied prior to the factorization + * such that the factorized matrix is P A P^-1. + * + * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower + * or Upper. Default is Lower. + * + * \sa class SimplicialLLT + */ +template + class SimplicialLDLT : public SimplicialCholeskyBase > +{ +public: + typedef _MatrixType MatrixType; + enum { UpLo = _UpLo }; + typedef SimplicialCholeskyBase Base; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + typedef SparseMatrix CholMatrixType; + typedef Matrix VectorType; + typedef internal::traits Traits; + typedef typename Traits::MatrixL MatrixL; + typedef typename Traits::MatrixU MatrixU; +public: + /** Default constructor */ + SimplicialLDLT() : Base() {} + + /** Constructs and performs the LLT factorization of \a matrix */ + SimplicialLDLT(const MatrixType& matrix) + : Base(matrix) {} + + /** \returns a vector expression of the diagonal D */ + inline const VectorType vectorD() const { + eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized"); + return Base::m_diag; + } + /** \returns an expression of the factor L */ + inline const MatrixL matrixL() const { + eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized"); + return Traits::getL(Base::m_matrix); + } + + /** \returns an expression of the factor U (= L^*) */ + inline const MatrixU matrixU() const { + eigen_assert(Base::m_factorizationIsOk && "Simplicial LDLT not factorized"); + return Traits::getU(Base::m_matrix); + } + + /** Computes the sparse Cholesky decomposition of \a matrix */ + SimplicialLDLT& compute(const MatrixType& matrix) + { + Base::template compute(matrix); + return *this; + } + + /** Performs a symbolic decomposition on the sparcity of \a matrix. + * + * This function is particularly useful when solving for several problems having the same structure. + * + * \sa factorize() + */ + void analyzePattern(const MatrixType& a) + { + Base::analyzePattern(a, true); + } + + /** Performs a numeric decomposition of \a matrix + * + * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. + * + * \sa analyzePattern() + */ + void factorize(const MatrixType& a) + { + Base::template factorize(a); + } + + /** \returns the determinant of the underlying matrix from the current factorization */ + Scalar determinant() const + { + return Base::m_diag.prod(); + } +}; + +/** \deprecated use SimplicialLDLT or class SimplicialLLT + * \ingroup SparseCholesky_Module + * \class SimplicialCholesky + * + * \sa class SimplicialLDLT, class SimplicialLLT + */ +template + class SimplicialCholesky : public SimplicialCholeskyBase > +{ +public: + typedef _MatrixType MatrixType; + enum { UpLo = _UpLo }; + typedef SimplicialCholeskyBase Base; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + typedef SparseMatrix CholMatrixType; + typedef Matrix VectorType; + typedef internal::traits Traits; + typedef internal::traits > LDLTTraits; + typedef internal::traits > LLTTraits; + public: + SimplicialCholesky() : Base(), m_LDLT(true) {} + + SimplicialCholesky(const MatrixType& matrix) + : Base(), m_LDLT(true) + { + compute(matrix); + } + + SimplicialCholesky& setMode(SimplicialCholeskyMode mode) + { + switch(mode) + { + case SimplicialCholeskyLLT: + m_LDLT = false; + break; + case SimplicialCholeskyLDLT: + m_LDLT = true; + break; + default: + break; + } + + return *this; + } + + inline const VectorType vectorD() const { + eigen_assert(Base::m_factorizationIsOk && "Simplicial Cholesky not factorized"); + return Base::m_diag; + } + inline const CholMatrixType rawMatrix() const { + eigen_assert(Base::m_factorizationIsOk && "Simplicial Cholesky not factorized"); + return Base::m_matrix; + } + + /** Computes the sparse Cholesky decomposition of \a matrix */ + SimplicialCholesky& compute(const MatrixType& matrix) + { + if(m_LDLT) + Base::template compute(matrix); + else + Base::template compute(matrix); + return *this; + } + + /** Performs a symbolic decomposition on the sparcity of \a matrix. + * + * This function is particularly useful when solving for several problems having the same structure. + * + * \sa factorize() + */ + void analyzePattern(const MatrixType& a) + { + Base::analyzePattern(a, m_LDLT); + } + + /** Performs a numeric decomposition of \a matrix + * + * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. + * + * \sa analyzePattern() + */ + void factorize(const MatrixType& a) + { + if(m_LDLT) + Base::template factorize(a); + else + Base::template factorize(a); + } + + /** \internal */ + template + void _solve(const MatrixBase &b, MatrixBase &dest) const + { + eigen_assert(Base::m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); + eigen_assert(Base::m_matrix.rows()==b.rows()); + + if(Base::m_info!=Success) + return; + + if(Base::m_P.size()>0) + dest = Base::m_P * b; + else + dest = b; + + if(Base::m_matrix.nonZeros()>0) // otherwise L==I + { + if(m_LDLT) + LDLTTraits::getL(Base::m_matrix).solveInPlace(dest); + else + LLTTraits::getL(Base::m_matrix).solveInPlace(dest); + } + + if(Base::m_diag.size()>0) + dest = Base::m_diag.asDiagonal().inverse() * dest; + + if (Base::m_matrix.nonZeros()>0) // otherwise I==I + { + if(m_LDLT) + LDLTTraits::getU(Base::m_matrix).solveInPlace(dest); + else + LLTTraits::getU(Base::m_matrix).solveInPlace(dest); + } + + if(Base::m_P.size()>0) + dest = Base::m_Pinv * dest; + } + + Scalar determinant() const + { + if(m_LDLT) + { + return Base::m_diag.prod(); + } + else + { + Scalar detL = Diagonal(Base::m_matrix).prod(); + return internal::abs2(detL); + } + } + + protected: + bool m_LDLT; +}; + +template +void SimplicialCholeskyBase::ordering(const MatrixType& a, CholMatrixType& ap) +{ + eigen_assert(a.rows()==a.cols()); + const Index size = a.rows(); + // TODO allows to configure the permutation + // Note that amd compute the inverse permutation + { + CholMatrixType C; + C = a.template selfadjointView(); + // remove diagonal entries: + // seems not to be needed + // C.prune(keep_diag()); + internal::minimum_degree_ordering(C, m_Pinv); + } + + if(m_Pinv.size()>0) + m_P = m_Pinv.inverse(); + else + m_P.resize(0); + + ap.resize(size,size); + ap.template selfadjointView() = a.template selfadjointView().twistedBy(m_P); +} + +template +void SimplicialCholeskyBase::analyzePattern_preordered(const CholMatrixType& ap, bool doLDLT) +{ + const Index size = ap.rows(); + m_matrix.resize(size, size); + m_parent.resize(size); + m_nonZerosPerCol.resize(size); + + ei_declare_aligned_stack_constructed_variable(Index, tags, size, 0); + + for(Index k = 0; k < size; ++k) + { + /* L(k,:) pattern: all nodes reachable in etree from nz in A(0:k-1,k) */ + m_parent[k] = -1; /* parent of k is not yet known */ + tags[k] = k; /* mark node k as visited */ + m_nonZerosPerCol[k] = 0; /* count of nonzeros in column k of L */ + for(typename CholMatrixType::InnerIterator it(ap,k); it; ++it) + { + Index i = it.index(); + if(i < k) + { + /* follow path from i to root of etree, stop at flagged node */ + for(; tags[i] != k; i = m_parent[i]) + { + /* find parent of i if not yet determined */ + if (m_parent[i] == -1) + m_parent[i] = k; + m_nonZerosPerCol[i]++; /* L (k,i) is nonzero */ + tags[i] = k; /* mark i as visited */ + } + } + } + } + + /* construct Lp index array from m_nonZerosPerCol column counts */ + Index* Lp = m_matrix.outerIndexPtr(); + Lp[0] = 0; + for(Index k = 0; k < size; ++k) + Lp[k+1] = Lp[k] + m_nonZerosPerCol[k] + (doLDLT ? 0 : 1); + + m_matrix.resizeNonZeros(Lp[size]); + + m_isInitialized = true; + m_info = Success; + m_analysisIsOk = true; + m_factorizationIsOk = false; +} + + +template +template +void SimplicialCholeskyBase::factorize_preordered(const CholMatrixType& ap) +{ + eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); + eigen_assert(ap.rows()==ap.cols()); + const Index size = ap.rows(); + eigen_assert(m_parent.size()==size); + eigen_assert(m_nonZerosPerCol.size()==size); + + const Index* Lp = m_matrix.outerIndexPtr(); + Index* Li = m_matrix.innerIndexPtr(); + Scalar* Lx = m_matrix.valuePtr(); + + ei_declare_aligned_stack_constructed_variable(Scalar, y, size, 0); + ei_declare_aligned_stack_constructed_variable(Index, pattern, size, 0); + ei_declare_aligned_stack_constructed_variable(Index, tags, size, 0); + + bool ok = true; + m_diag.resize(DoLDLT ? size : 0); + + for(Index k = 0; k < size; ++k) + { + // compute nonzero pattern of kth row of L, in topological order + y[k] = 0.0; // Y(0:k) is now all zero + Index top = size; // stack for pattern is empty + tags[k] = k; // mark node k as visited + m_nonZerosPerCol[k] = 0; // count of nonzeros in column k of L + for(typename MatrixType::InnerIterator it(ap,k); it; ++it) + { + Index i = it.index(); + if(i <= k) + { + y[i] += internal::conj(it.value()); /* scatter A(i,k) into Y (sum duplicates) */ + Index len; + for(len = 0; tags[i] != k; i = m_parent[i]) + { + pattern[len++] = i; /* L(k,i) is nonzero */ + tags[i] = k; /* mark i as visited */ + } + while(len > 0) + pattern[--top] = pattern[--len]; + } + } + + /* compute numerical values kth row of L (a sparse triangular solve) */ + + RealScalar d = internal::real(y[k]) * m_shiftScale + m_shiftOffset; // get D(k,k), apply the shift function, and clear Y(k) + y[k] = 0.0; + for(; top < size; ++top) + { + Index i = pattern[top]; /* pattern[top:n-1] is pattern of L(:,k) */ + Scalar yi = y[i]; /* get and clear Y(i) */ + y[i] = 0.0; + + /* the nonzero entry L(k,i) */ + Scalar l_ki; + if(DoLDLT) + l_ki = yi / m_diag[i]; + else + yi = l_ki = yi / Lx[Lp[i]]; + + Index p2 = Lp[i] + m_nonZerosPerCol[i]; + Index p; + for(p = Lp[i] + (DoLDLT ? 0 : 1); p < p2; ++p) + y[Li[p]] -= internal::conj(Lx[p]) * yi; + d -= internal::real(l_ki * internal::conj(yi)); + Li[p] = k; /* store L(k,i) in column form of L */ + Lx[p] = l_ki; + ++m_nonZerosPerCol[i]; /* increment count of nonzeros in col i */ + } + if(DoLDLT) + { + m_diag[k] = d; + if(d == RealScalar(0)) + { + ok = false; /* failure, D(k,k) is zero */ + break; + } + } + else + { + Index p = Lp[k] + m_nonZerosPerCol[k]++; + Li[p] = k ; /* store L(k,k) = sqrt (d) in column k */ + if(d <= RealScalar(0)) { + ok = false; /* failure, matrix is not positive definite */ + break; + } + Lx[p] = internal::sqrt(d) ; + } + } + + m_info = ok ? Success : NumericalIssue; + m_factorizationIsOk = true; +} + +namespace internal { + +template +struct solve_retval, Rhs> + : solve_retval_base, Rhs> +{ + typedef SimplicialCholeskyBase Dec; + EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec().derived()._solve(rhs(),dst); + } +}; + +template +struct sparse_solve_retval, Rhs> + : sparse_solve_retval_base, Rhs> +{ + typedef SimplicialCholeskyBase Dec; + EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec().derived()._solve_sparse(rhs(),dst); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_SIMPLICIAL_CHOLESKY_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/AmbiVector.h b/extern/Eigen3/Eigen/src/SparseCore/AmbiVector.h new file mode 100644 index 00000000000..6cfaadbaa9a --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/AmbiVector.h @@ -0,0 +1,371 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_AMBIVECTOR_H +#define EIGEN_AMBIVECTOR_H + +namespace Eigen { + +namespace internal { + +/** \internal + * Hybrid sparse/dense vector class designed for intensive read-write operations. + * + * See BasicSparseLLT and SparseProduct for usage examples. + */ +template +class AmbiVector +{ + public: + typedef _Scalar Scalar; + typedef _Index Index; + typedef typename NumTraits::Real RealScalar; + + AmbiVector(Index size) + : m_buffer(0), m_zero(0), m_size(0), m_allocatedSize(0), m_allocatedElements(0), m_mode(-1) + { + resize(size); + } + + void init(double estimatedDensity); + void init(int mode); + + Index nonZeros() const; + + /** Specifies a sub-vector to work on */ + void setBounds(Index start, Index end) { m_start = start; m_end = end; } + + void setZero(); + + void restart(); + Scalar& coeffRef(Index i); + Scalar& coeff(Index i); + + class Iterator; + + ~AmbiVector() { delete[] m_buffer; } + + void resize(Index size) + { + if (m_allocatedSize < size) + reallocate(size); + m_size = size; + } + + Index size() const { return m_size; } + + protected: + + void reallocate(Index size) + { + // if the size of the matrix is not too large, let's allocate a bit more than needed such + // that we can handle dense vector even in sparse mode. + delete[] m_buffer; + if (size<1000) + { + Index allocSize = (size * sizeof(ListEl))/sizeof(Scalar); + m_allocatedElements = (allocSize*sizeof(Scalar))/sizeof(ListEl); + m_buffer = new Scalar[allocSize]; + } + else + { + m_allocatedElements = (size*sizeof(Scalar))/sizeof(ListEl); + m_buffer = new Scalar[size]; + } + m_size = size; + m_start = 0; + m_end = m_size; + } + + void reallocateSparse() + { + Index copyElements = m_allocatedElements; + m_allocatedElements = (std::min)(Index(m_allocatedElements*1.5),m_size); + Index allocSize = m_allocatedElements * sizeof(ListEl); + allocSize = allocSize/sizeof(Scalar) + (allocSize%sizeof(Scalar)>0?1:0); + Scalar* newBuffer = new Scalar[allocSize]; + memcpy(newBuffer, m_buffer, copyElements * sizeof(ListEl)); + delete[] m_buffer; + m_buffer = newBuffer; + } + + protected: + // element type of the linked list + struct ListEl + { + Index next; + Index index; + Scalar value; + }; + + // used to store data in both mode + Scalar* m_buffer; + Scalar m_zero; + Index m_size; + Index m_start; + Index m_end; + Index m_allocatedSize; + Index m_allocatedElements; + Index m_mode; + + // linked list mode + Index m_llStart; + Index m_llCurrent; + Index m_llSize; +}; + +/** \returns the number of non zeros in the current sub vector */ +template +_Index AmbiVector<_Scalar,_Index>::nonZeros() const +{ + if (m_mode==IsSparse) + return m_llSize; + else + return m_end - m_start; +} + +template +void AmbiVector<_Scalar,_Index>::init(double estimatedDensity) +{ + if (estimatedDensity>0.1) + init(IsDense); + else + init(IsSparse); +} + +template +void AmbiVector<_Scalar,_Index>::init(int mode) +{ + m_mode = mode; + if (m_mode==IsSparse) + { + m_llSize = 0; + m_llStart = -1; + } +} + +/** Must be called whenever we might perform a write access + * with an index smaller than the previous one. + * + * Don't worry, this function is extremely cheap. + */ +template +void AmbiVector<_Scalar,_Index>::restart() +{ + m_llCurrent = m_llStart; +} + +/** Set all coefficients of current subvector to zero */ +template +void AmbiVector<_Scalar,_Index>::setZero() +{ + if (m_mode==IsDense) + { + for (Index i=m_start; i +_Scalar& AmbiVector<_Scalar,_Index>::coeffRef(_Index i) +{ + if (m_mode==IsDense) + return m_buffer[i]; + else + { + ListEl* EIGEN_RESTRICT llElements = reinterpret_cast(m_buffer); + // TODO factorize the following code to reduce code generation + eigen_assert(m_mode==IsSparse); + if (m_llSize==0) + { + // this is the first element + m_llStart = 0; + m_llCurrent = 0; + ++m_llSize; + llElements[0].value = Scalar(0); + llElements[0].index = i; + llElements[0].next = -1; + return llElements[0].value; + } + else if (i=llElements[m_llCurrent].index && "you must call restart() before inserting an element with lower or equal index"); + while (nextel >= 0 && llElements[nextel].index<=i) + { + m_llCurrent = nextel; + nextel = llElements[nextel].next; + } + + if (llElements[m_llCurrent].index==i) + { + // the coefficient already exists and we found it ! + return llElements[m_llCurrent].value; + } + else + { + if (m_llSize>=m_allocatedElements) + { + reallocateSparse(); + llElements = reinterpret_cast(m_buffer); + } + eigen_internal_assert(m_llSize +_Scalar& AmbiVector<_Scalar,_Index>::coeff(_Index i) +{ + if (m_mode==IsDense) + return m_buffer[i]; + else + { + ListEl* EIGEN_RESTRICT llElements = reinterpret_cast(m_buffer); + eigen_assert(m_mode==IsSparse); + if ((m_llSize==0) || (i= 0 && llElements[elid].index +class AmbiVector<_Scalar,_Index>::Iterator +{ + public: + typedef _Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + + /** Default constructor + * \param vec the vector on which we iterate + * \param epsilon the minimal value used to prune zero coefficients. + * In practice, all coefficients having a magnitude smaller than \a epsilon + * are skipped. + */ + Iterator(const AmbiVector& vec, RealScalar epsilon = 0) + : m_vector(vec) + { + m_epsilon = epsilon; + m_isDense = m_vector.m_mode==IsDense; + if (m_isDense) + { + m_currentEl = 0; // this is to avoid a compilation warning + m_cachedValue = 0; // this is to avoid a compilation warning + m_cachedIndex = m_vector.m_start-1; + ++(*this); + } + else + { + ListEl* EIGEN_RESTRICT llElements = reinterpret_cast(m_vector.m_buffer); + m_currentEl = m_vector.m_llStart; + while (m_currentEl>=0 && internal::abs(llElements[m_currentEl].value)<=m_epsilon) + m_currentEl = llElements[m_currentEl].next; + if (m_currentEl<0) + { + m_cachedValue = 0; // this is to avoid a compilation warning + m_cachedIndex = -1; + } + else + { + m_cachedIndex = llElements[m_currentEl].index; + m_cachedValue = llElements[m_currentEl].value; + } + } + } + + Index index() const { return m_cachedIndex; } + Scalar value() const { return m_cachedValue; } + + operator bool() const { return m_cachedIndex>=0; } + + Iterator& operator++() + { + if (m_isDense) + { + do { + ++m_cachedIndex; + } while (m_cachedIndex(m_vector.m_buffer); + do { + m_currentEl = llElements[m_currentEl].next; + } while (m_currentEl>=0 && internal::abs(llElements[m_currentEl].value) +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_COMPRESSED_STORAGE_H +#define EIGEN_COMPRESSED_STORAGE_H + +namespace Eigen { + +namespace internal { + +/** \internal + * Stores a sparse set of values as a list of values and a list of indices. + * + */ +template +class CompressedStorage +{ + public: + + typedef _Scalar Scalar; + typedef _Index Index; + + protected: + + typedef typename NumTraits::Real RealScalar; + + public: + + CompressedStorage() + : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0) + {} + + CompressedStorage(size_t size) + : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0) + { + resize(size); + } + + CompressedStorage(const CompressedStorage& other) + : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0) + { + *this = other; + } + + CompressedStorage& operator=(const CompressedStorage& other) + { + resize(other.size()); + memcpy(m_values, other.m_values, m_size * sizeof(Scalar)); + memcpy(m_indices, other.m_indices, m_size * sizeof(Index)); + return *this; + } + + void swap(CompressedStorage& other) + { + std::swap(m_values, other.m_values); + std::swap(m_indices, other.m_indices); + std::swap(m_size, other.m_size); + std::swap(m_allocatedSize, other.m_allocatedSize); + } + + ~CompressedStorage() + { + delete[] m_values; + delete[] m_indices; + } + + void reserve(size_t size) + { + size_t newAllocatedSize = m_size + size; + if (newAllocatedSize > m_allocatedSize) + reallocate(newAllocatedSize); + } + + void squeeze() + { + if (m_allocatedSize>m_size) + reallocate(m_size); + } + + void resize(size_t size, float reserveSizeFactor = 0) + { + if (m_allocatedSize(m_size); + resize(m_size+1, 1); + m_values[id] = v; + m_indices[id] = i; + } + + inline size_t size() const { return m_size; } + inline size_t allocatedSize() const { return m_allocatedSize; } + inline void clear() { m_size = 0; } + + inline Scalar& value(size_t i) { return m_values[i]; } + inline const Scalar& value(size_t i) const { return m_values[i]; } + + inline Index& index(size_t i) { return m_indices[i]; } + inline const Index& index(size_t i) const { return m_indices[i]; } + + static CompressedStorage Map(Index* indices, Scalar* values, size_t size) + { + CompressedStorage res; + res.m_indices = indices; + res.m_values = values; + res.m_allocatedSize = res.m_size = size; + return res; + } + + /** \returns the largest \c k such that for all \c j in [0,k) index[\c j]\<\a key */ + inline Index searchLowerIndex(Index key) const + { + return searchLowerIndex(0, m_size, key); + } + + /** \returns the largest \c k in [start,end) such that for all \c j in [start,k) index[\c j]\<\a key */ + inline Index searchLowerIndex(size_t start, size_t end, Index key) const + { + while(end>start) + { + size_t mid = (end+start)>>1; + if (m_indices[mid](start); + } + + /** \returns the stored value at index \a key + * If the value does not exist, then the value \a defaultValue is returned without any insertion. */ + inline Scalar at(Index key, Scalar defaultValue = Scalar(0)) const + { + if (m_size==0) + return defaultValue; + else if (key==m_indices[m_size-1]) + return m_values[m_size-1]; + // ^^ optimization: let's first check if it is the last coefficient + // (very common in high level algorithms) + const size_t id = searchLowerIndex(0,m_size-1,key); + return ((id=end) + return Scalar(0); + else if (end>start && key==m_indices[end-1]) + return m_values[end-1]; + // ^^ optimization: let's first check if it is the last coefficient + // (very common in high level algorithms) + const size_t id = searchLowerIndex(start,end-1,key); + return ((id=m_size || m_indices[id]!=key) + { + resize(m_size+1,1); + for (size_t j=m_size-1; j>id; --j) + { + m_indices[j] = m_indices[j-1]; + m_values[j] = m_values[j-1]; + } + m_indices[id] = key; + m_values[id] = defaultValue; + } + return m_values[id]; + } + + void prune(Scalar reference, RealScalar epsilon = NumTraits::dummy_precision()) + { + size_t k = 0; + size_t n = size(); + for (size_t i=0; i +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CONSERVATIVESPARSESPARSEPRODUCT_H +#define EIGEN_CONSERVATIVESPARSESPARSEPRODUCT_H + +namespace Eigen { + +namespace internal { + +template +static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& rhs, ResultType& res) +{ + typedef typename remove_all::type::Scalar Scalar; + typedef typename remove_all::type::Index Index; + + // make sure to call innerSize/outerSize since we fake the storage order. + Index rows = lhs.innerSize(); + Index cols = rhs.outerSize(); + eigen_assert(lhs.outerSize() == rhs.innerSize()); + + std::vector mask(rows,false); + Matrix values(rows); + Matrix indices(rows); + + // estimate the number of non zero entries + // given a rhs column containing Y non zeros, we assume that the respective Y columns + // of the lhs differs in average of one non zeros, thus the number of non zeros for + // the product of a rhs column with the lhs is X+Y where X is the average number of non zero + // per column of the lhs. + // Therefore, we have nnz(lhs*rhs) = nnz(lhs) + nnz(rhs) + Index estimated_nnz_prod = lhs.nonZeros() + rhs.nonZeros(); + + res.setZero(); + res.reserve(Index(estimated_nnz_prod)); + // we compute each column of the result, one after the other + for (Index j=0; j use a quick sort + // otherwise => loop through the entire vector + // In order to avoid to perform an expensive log2 when the + // result is clearly very sparse we use a linear bound up to 200. + //if((nnz<200 && nnz1) std::sort(indices.data(),indices.data()+nnz); + for(int k=0; k::Flags&RowMajorBit, + int RhsStorageOrder = traits::Flags&RowMajorBit, + int ResStorageOrder = traits::Flags&RowMajorBit> +struct conservative_sparse_sparse_product_selector; + +template +struct conservative_sparse_sparse_product_selector +{ + typedef typename remove_all::type LhsCleaned; + typedef typename LhsCleaned::Scalar Scalar; + + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) + { + typedef SparseMatrix RowMajorMatrix; + typedef SparseMatrix ColMajorMatrix; + ColMajorMatrix resCol(lhs.rows(),rhs.cols()); + internal::conservative_sparse_sparse_product_impl(lhs, rhs, resCol); + // sort the non zeros: + RowMajorMatrix resRow(resCol); + res = resRow; + } +}; + +template +struct conservative_sparse_sparse_product_selector +{ + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) + { + typedef SparseMatrix RowMajorMatrix; + RowMajorMatrix rhsRow = rhs; + RowMajorMatrix resRow(lhs.rows(), rhs.cols()); + internal::conservative_sparse_sparse_product_impl(rhsRow, lhs, resRow); + res = resRow; + } +}; + +template +struct conservative_sparse_sparse_product_selector +{ + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) + { + typedef SparseMatrix RowMajorMatrix; + RowMajorMatrix lhsRow = lhs; + RowMajorMatrix resRow(lhs.rows(), rhs.cols()); + internal::conservative_sparse_sparse_product_impl(rhs, lhsRow, resRow); + res = resRow; + } +}; + +template +struct conservative_sparse_sparse_product_selector +{ + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) + { + typedef SparseMatrix RowMajorMatrix; + RowMajorMatrix resRow(lhs.rows(), rhs.cols()); + internal::conservative_sparse_sparse_product_impl(rhs, lhs, resRow); + res = resRow; + } +}; + + +template +struct conservative_sparse_sparse_product_selector +{ + typedef typename traits::type>::Scalar Scalar; + + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) + { + typedef SparseMatrix ColMajorMatrix; + ColMajorMatrix resCol(lhs.rows(), rhs.cols()); + internal::conservative_sparse_sparse_product_impl(lhs, rhs, resCol); + res = resCol; + } +}; + +template +struct conservative_sparse_sparse_product_selector +{ + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) + { + typedef SparseMatrix ColMajorMatrix; + ColMajorMatrix lhsCol = lhs; + ColMajorMatrix resCol(lhs.rows(), rhs.cols()); + internal::conservative_sparse_sparse_product_impl(lhsCol, rhs, resCol); + res = resCol; + } +}; + +template +struct conservative_sparse_sparse_product_selector +{ + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) + { + typedef SparseMatrix ColMajorMatrix; + ColMajorMatrix rhsCol = rhs; + ColMajorMatrix resCol(lhs.rows(), rhs.cols()); + internal::conservative_sparse_sparse_product_impl(lhs, rhsCol, resCol); + res = resCol; + } +}; + +template +struct conservative_sparse_sparse_product_selector +{ + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) + { + typedef SparseMatrix RowMajorMatrix; + typedef SparseMatrix ColMajorMatrix; + RowMajorMatrix resRow(lhs.rows(),rhs.cols()); + internal::conservative_sparse_sparse_product_impl(rhs, lhs, resRow); + // sort the non zeros: + ColMajorMatrix resCol(resRow); + res = resCol; + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_CONSERVATIVESPARSESPARSEPRODUCT_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/CoreIterators.h b/extern/Eigen3/Eigen/src/SparseCore/CoreIterators.h new file mode 100644 index 00000000000..6da4683d2c2 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/CoreIterators.h @@ -0,0 +1,61 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_COREITERATORS_H +#define EIGEN_COREITERATORS_H + +namespace Eigen { + +/* This file contains the respective InnerIterator definition of the expressions defined in Eigen/Core + */ + +/** \ingroup SparseCore_Module + * \class InnerIterator + * \brief An InnerIterator allows to loop over the element of a sparse (or dense) matrix or expression + * + * todo + */ + +// generic version for dense matrix and expressions +template class DenseBase::InnerIterator +{ + protected: + typedef typename Derived::Scalar Scalar; + typedef typename Derived::Index Index; + + enum { IsRowMajor = (Derived::Flags&RowMajorBit)==RowMajorBit }; + public: + EIGEN_STRONG_INLINE InnerIterator(const Derived& expr, Index outer) + : m_expression(expr), m_inner(0), m_outer(outer), m_end(expr.innerSize()) + {} + + EIGEN_STRONG_INLINE Scalar value() const + { + return (IsRowMajor) ? m_expression.coeff(m_outer, m_inner) + : m_expression.coeff(m_inner, m_outer); + } + + EIGEN_STRONG_INLINE InnerIterator& operator++() { m_inner++; return *this; } + + EIGEN_STRONG_INLINE Index index() const { return m_inner; } + inline Index row() const { return IsRowMajor ? m_outer : index(); } + inline Index col() const { return IsRowMajor ? index() : m_outer; } + + EIGEN_STRONG_INLINE operator bool() const { return m_inner < m_end && m_inner>=0; } + + protected: + const Derived& m_expression; + Index m_inner; + const Index m_outer; + const Index m_end; +}; + +} // end namespace Eigen + +#endif // EIGEN_COREITERATORS_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/MappedSparseMatrix.h b/extern/Eigen3/Eigen/src/SparseCore/MappedSparseMatrix.h new file mode 100644 index 00000000000..93cd4832dea --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/MappedSparseMatrix.h @@ -0,0 +1,179 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MAPPED_SPARSEMATRIX_H +#define EIGEN_MAPPED_SPARSEMATRIX_H + +namespace Eigen { + +/** \class MappedSparseMatrix + * + * \brief Sparse matrix + * + * \param _Scalar the scalar type, i.e. the type of the coefficients + * + * See http://www.netlib.org/linalg/html_templates/node91.html for details on the storage scheme. + * + */ +namespace internal { +template +struct traits > : traits > +{}; +} + +template +class MappedSparseMatrix + : public SparseMatrixBase > +{ + public: + EIGEN_SPARSE_PUBLIC_INTERFACE(MappedSparseMatrix) + enum { IsRowMajor = Base::IsRowMajor }; + + protected: + + Index m_outerSize; + Index m_innerSize; + Index m_nnz; + Index* m_outerIndex; + Index* m_innerIndices; + Scalar* m_values; + + public: + + inline Index rows() const { return IsRowMajor ? m_outerSize : m_innerSize; } + inline Index cols() const { return IsRowMajor ? m_innerSize : m_outerSize; } + inline Index innerSize() const { return m_innerSize; } + inline Index outerSize() const { return m_outerSize; } + + //---------------------------------------- + // direct access interface + inline const Scalar* valuePtr() const { return m_values; } + inline Scalar* valuePtr() { return m_values; } + + inline const Index* innerIndexPtr() const { return m_innerIndices; } + inline Index* innerIndexPtr() { return m_innerIndices; } + + inline const Index* outerIndexPtr() const { return m_outerIndex; } + inline Index* outerIndexPtr() { return m_outerIndex; } + //---------------------------------------- + + inline Scalar coeff(Index row, Index col) const + { + const Index outer = IsRowMajor ? row : col; + const Index inner = IsRowMajor ? col : row; + + Index start = m_outerIndex[outer]; + Index end = m_outerIndex[outer+1]; + if (start==end) + return Scalar(0); + else if (end>0 && inner==m_innerIndices[end-1]) + return m_values[end-1]; + // ^^ optimization: let's first check if it is the last coefficient + // (very common in high level algorithms) + + const Index* r = std::lower_bound(&m_innerIndices[start],&m_innerIndices[end-1],inner); + const Index id = r-&m_innerIndices[0]; + return ((*r==inner) && (id=start && "you probably called coeffRef on a non finalized matrix"); + eigen_assert(end>start && "coeffRef cannot be called on a zero coefficient"); + Index* r = std::lower_bound(&m_innerIndices[start],&m_innerIndices[end],inner); + const Index id = r-&m_innerIndices[0]; + eigen_assert((*r==inner) && (id +class MappedSparseMatrix::InnerIterator +{ + public: + InnerIterator(const MappedSparseMatrix& mat, Index outer) + : m_matrix(mat), + m_outer(outer), + m_id(mat.outerIndexPtr()[outer]), + m_start(m_id), + m_end(mat.outerIndexPtr()[outer+1]) + {} + + inline InnerIterator& operator++() { m_id++; return *this; } + + inline Scalar value() const { return m_matrix.valuePtr()[m_id]; } + inline Scalar& valueRef() { return const_cast(m_matrix.valuePtr()[m_id]); } + + inline Index index() const { return m_matrix.innerIndexPtr()[m_id]; } + inline Index row() const { return IsRowMajor ? m_outer : index(); } + inline Index col() const { return IsRowMajor ? index() : m_outer; } + + inline operator bool() const { return (m_id < m_end) && (m_id>=m_start); } + + protected: + const MappedSparseMatrix& m_matrix; + const Index m_outer; + Index m_id; + const Index m_start; + const Index m_end; +}; + +template +class MappedSparseMatrix::ReverseInnerIterator +{ + public: + ReverseInnerIterator(const MappedSparseMatrix& mat, Index outer) + : m_matrix(mat), + m_outer(outer), + m_id(mat.outerIndexPtr()[outer+1]), + m_start(mat.outerIndexPtr()[outer]), + m_end(m_id) + {} + + inline ReverseInnerIterator& operator--() { m_id--; return *this; } + + inline Scalar value() const { return m_matrix.valuePtr()[m_id-1]; } + inline Scalar& valueRef() { return const_cast(m_matrix.valuePtr()[m_id-1]); } + + inline Index index() const { return m_matrix.innerIndexPtr()[m_id-1]; } + inline Index row() const { return IsRowMajor ? m_outer : index(); } + inline Index col() const { return IsRowMajor ? index() : m_outer; } + + inline operator bool() const { return (m_id <= m_end) && (m_id>m_start); } + + protected: + const MappedSparseMatrix& m_matrix; + const Index m_outer; + Index m_id; + const Index m_start; + const Index m_end; +}; + +} // end namespace Eigen + +#endif // EIGEN_MAPPED_SPARSEMATRIX_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseAssign.h b/extern/Eigen3/Eigen/src/SparseCore/SparseAssign.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseBlock.h b/extern/Eigen3/Eigen/src/SparseCore/SparseBlock.h new file mode 100644 index 00000000000..eefd8070251 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseBlock.h @@ -0,0 +1,387 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSE_BLOCK_H +#define EIGEN_SPARSE_BLOCK_H + +namespace Eigen { + +namespace internal { +template +struct traits > +{ + typedef typename traits::Scalar Scalar; + typedef typename traits::Index Index; + typedef typename traits::StorageKind StorageKind; + typedef MatrixXpr XprKind; + enum { + IsRowMajor = (int(MatrixType::Flags)&RowMajorBit)==RowMajorBit, + Flags = MatrixType::Flags, + RowsAtCompileTime = IsRowMajor ? Size : MatrixType::RowsAtCompileTime, + ColsAtCompileTime = IsRowMajor ? MatrixType::ColsAtCompileTime : Size, + MaxRowsAtCompileTime = RowsAtCompileTime, + MaxColsAtCompileTime = ColsAtCompileTime, + CoeffReadCost = MatrixType::CoeffReadCost + }; +}; +} // end namespace internal + +template +class SparseInnerVectorSet : internal::no_assignment_operator, + public SparseMatrixBase > +{ + public: + + enum { IsRowMajor = internal::traits::IsRowMajor }; + + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseInnerVectorSet) + class InnerIterator: public MatrixType::InnerIterator + { + public: + inline InnerIterator(const SparseInnerVectorSet& xpr, Index outer) + : MatrixType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) + {} + inline Index row() const { return IsRowMajor ? m_outer : this->index(); } + inline Index col() const { return IsRowMajor ? this->index() : m_outer; } + protected: + Index m_outer; + }; + class ReverseInnerIterator: public MatrixType::ReverseInnerIterator + { + public: + inline ReverseInnerIterator(const SparseInnerVectorSet& xpr, Index outer) + : MatrixType::ReverseInnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) + {} + inline Index row() const { return IsRowMajor ? m_outer : this->index(); } + inline Index col() const { return IsRowMajor ? this->index() : m_outer; } + protected: + Index m_outer; + }; + + inline SparseInnerVectorSet(const MatrixType& matrix, Index outerStart, Index outerSize) + : m_matrix(matrix), m_outerStart(outerStart), m_outerSize(outerSize) + { + eigen_assert( (outerStart>=0) && ((outerStart+outerSize)<=matrix.outerSize()) ); + } + + inline SparseInnerVectorSet(const MatrixType& matrix, Index outer) + : m_matrix(matrix), m_outerStart(outer), m_outerSize(Size) + { + eigen_assert(Size!=Dynamic); + eigen_assert( (outer>=0) && (outer +// inline SparseInnerVectorSet& operator=(const SparseMatrixBase& other) +// { +// return *this; +// } + +// template +// inline SparseInnerVectorSet& operator=(const SparseMatrixBase& other) +// { +// return *this; +// } + + EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); } + EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); } + + protected: + + const typename MatrixType::Nested m_matrix; + Index m_outerStart; + const internal::variable_if_dynamic m_outerSize; +}; + + +/*************************************************************************** +* specialisation for SparseMatrix +***************************************************************************/ + +template +class SparseInnerVectorSet, Size> + : public SparseMatrixBase, Size> > +{ + typedef SparseMatrix<_Scalar, _Options, _Index> MatrixType; + public: + + enum { IsRowMajor = internal::traits::IsRowMajor }; + + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseInnerVectorSet) + class InnerIterator: public MatrixType::InnerIterator + { + public: + inline InnerIterator(const SparseInnerVectorSet& xpr, Index outer) + : MatrixType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) + {} + inline Index row() const { return IsRowMajor ? m_outer : this->index(); } + inline Index col() const { return IsRowMajor ? this->index() : m_outer; } + protected: + Index m_outer; + }; + class ReverseInnerIterator: public MatrixType::ReverseInnerIterator + { + public: + inline ReverseInnerIterator(const SparseInnerVectorSet& xpr, Index outer) + : MatrixType::ReverseInnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) + {} + inline Index row() const { return IsRowMajor ? m_outer : this->index(); } + inline Index col() const { return IsRowMajor ? this->index() : m_outer; } + protected: + Index m_outer; + }; + + inline SparseInnerVectorSet(const MatrixType& matrix, Index outerStart, Index outerSize) + : m_matrix(matrix), m_outerStart(outerStart), m_outerSize(outerSize) + { + eigen_assert( (outerStart>=0) && ((outerStart+outerSize)<=matrix.outerSize()) ); + } + + inline SparseInnerVectorSet(const MatrixType& matrix, Index outer) + : m_matrix(matrix), m_outerStart(outer), m_outerSize(Size) + { + eigen_assert(Size==1); + eigen_assert( (outer>=0) && (outer + inline SparseInnerVectorSet& operator=(const SparseMatrixBase& other) + { + typedef typename internal::remove_all::type _NestedMatrixType; + _NestedMatrixType& matrix = const_cast<_NestedMatrixType&>(m_matrix);; + // This assignement is slow if this vector set is not empty + // and/or it is not at the end of the nonzeros of the underlying matrix. + + // 1 - eval to a temporary to avoid transposition and/or aliasing issues + SparseMatrix tmp(other); + + // 2 - let's check whether there is enough allocated memory + Index nnz = tmp.nonZeros(); + Index nnz_previous = nonZeros(); + Index free_size = Index(matrix.data().allocatedSize()) + nnz_previous; + Index nnz_head = m_outerStart==0 ? 0 : matrix.outerIndexPtr()[m_outerStart]; + Index tail = m_matrix.outerIndexPtr()[m_outerStart+m_outerSize.value()]; + Index nnz_tail = matrix.nonZeros() - tail; + + if(nnz>free_size) + { + // realloc manually to reduce copies + typename MatrixType::Storage newdata(m_matrix.nonZeros() - nnz_previous + nnz); + + std::memcpy(&newdata.value(0), &m_matrix.data().value(0), nnz_head*sizeof(Scalar)); + std::memcpy(&newdata.index(0), &m_matrix.data().index(0), nnz_head*sizeof(Index)); + + std::memcpy(&newdata.value(nnz_head), &tmp.data().value(0), nnz*sizeof(Scalar)); + std::memcpy(&newdata.index(nnz_head), &tmp.data().index(0), nnz*sizeof(Index)); + + std::memcpy(&newdata.value(nnz_head+nnz), &matrix.data().value(tail), nnz_tail*sizeof(Scalar)); + std::memcpy(&newdata.index(nnz_head+nnz), &matrix.data().index(tail), nnz_tail*sizeof(Index)); + + matrix.data().swap(newdata); + } + else + { + // no need to realloc, simply copy the tail at its respective position and insert tmp + matrix.data().resize(nnz_head + nnz + nnz_tail); + + if(nnz=0; --i) + { + matrix.data().value(nnz_head+nnz+i) = matrix.data().value(tail+i); + matrix.data().index(nnz_head+nnz+i) = matrix.data().index(tail+i); + } + } + + std::memcpy(&matrix.data().value(nnz_head), &tmp.data().value(0), nnz*sizeof(Scalar)); + std::memcpy(&matrix.data().index(nnz_head), &tmp.data().index(0), nnz*sizeof(Index)); + } + + // update outer index pointers + Index p = nnz_head; + for(Index k=0; k(other); + } + + inline const Scalar* valuePtr() const + { return m_matrix.valuePtr() + m_matrix.outerIndexPtr()[m_outerStart]; } + inline Scalar* valuePtr() + { return m_matrix.const_cast_derived().valuePtr() + m_matrix.outerIndexPtr()[m_outerStart]; } + + inline const Index* innerIndexPtr() const + { return m_matrix.innerIndexPtr() + m_matrix.outerIndexPtr()[m_outerStart]; } + inline Index* innerIndexPtr() + { return m_matrix.const_cast_derived().innerIndexPtr() + m_matrix.outerIndexPtr()[m_outerStart]; } + + inline const Index* outerIndexPtr() const + { return m_matrix.outerIndexPtr() + m_outerStart; } + inline Index* outerIndexPtr() + { return m_matrix.const_cast_derived().outerIndexPtr() + m_outerStart; } + + Index nonZeros() const + { + if(m_matrix.isCompressed()) + return std::size_t(m_matrix.outerIndexPtr()[m_outerStart+m_outerSize.value()]) + - std::size_t(m_matrix.outerIndexPtr()[m_outerStart]); + else if(m_outerSize.value()==0) + return 0; + else + return Map >(m_matrix.innerNonZeroPtr()+m_outerStart, m_outerSize.value()).sum(); + } + + const Scalar& lastCoeff() const + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(SparseInnerVectorSet); + eigen_assert(nonZeros()>0); + if(m_matrix.isCompressed()) + return m_matrix.valuePtr()[m_matrix.outerIndexPtr()[m_outerStart+1]-1]; + else + return m_matrix.valuePtr()[m_matrix.outerIndexPtr()[m_outerStart]+m_matrix.innerNonZeroPtr()[m_outerStart]-1]; + } + +// template +// inline SparseInnerVectorSet& operator=(const SparseMatrixBase& other) +// { +// return *this; +// } + + EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); } + EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); } + + protected: + + typename MatrixType::Nested m_matrix; + Index m_outerStart; + const internal::variable_if_dynamic m_outerSize; + +}; + +//---------- + +/** \returns the i-th row of the matrix \c *this. For row-major matrix only. */ +template +SparseInnerVectorSet SparseMatrixBase::row(Index i) +{ + EIGEN_STATIC_ASSERT(IsRowMajor,THIS_METHOD_IS_ONLY_FOR_ROW_MAJOR_MATRICES); + return innerVector(i); +} + +/** \returns the i-th row of the matrix \c *this. For row-major matrix only. + * (read-only version) */ +template +const SparseInnerVectorSet SparseMatrixBase::row(Index i) const +{ + EIGEN_STATIC_ASSERT(IsRowMajor,THIS_METHOD_IS_ONLY_FOR_ROW_MAJOR_MATRICES); + return innerVector(i); +} + +/** \returns the i-th column of the matrix \c *this. For column-major matrix only. */ +template +SparseInnerVectorSet SparseMatrixBase::col(Index i) +{ + EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); + return innerVector(i); +} + +/** \returns the i-th column of the matrix \c *this. For column-major matrix only. + * (read-only version) */ +template +const SparseInnerVectorSet SparseMatrixBase::col(Index i) const +{ + EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); + return innerVector(i); +} + +/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this + * is col-major (resp. row-major). + */ +template +SparseInnerVectorSet SparseMatrixBase::innerVector(Index outer) +{ return SparseInnerVectorSet(derived(), outer); } + +/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this + * is col-major (resp. row-major). Read-only. + */ +template +const SparseInnerVectorSet SparseMatrixBase::innerVector(Index outer) const +{ return SparseInnerVectorSet(derived(), outer); } + +/** \returns the i-th row of the matrix \c *this. For row-major matrix only. */ +template +SparseInnerVectorSet SparseMatrixBase::middleRows(Index start, Index size) +{ + EIGEN_STATIC_ASSERT(IsRowMajor,THIS_METHOD_IS_ONLY_FOR_ROW_MAJOR_MATRICES); + return innerVectors(start, size); +} + +/** \returns the i-th row of the matrix \c *this. For row-major matrix only. + * (read-only version) */ +template +const SparseInnerVectorSet SparseMatrixBase::middleRows(Index start, Index size) const +{ + EIGEN_STATIC_ASSERT(IsRowMajor,THIS_METHOD_IS_ONLY_FOR_ROW_MAJOR_MATRICES); + return innerVectors(start, size); +} + +/** \returns the i-th column of the matrix \c *this. For column-major matrix only. */ +template +SparseInnerVectorSet SparseMatrixBase::middleCols(Index start, Index size) +{ + EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); + return innerVectors(start, size); +} + +/** \returns the i-th column of the matrix \c *this. For column-major matrix only. + * (read-only version) */ +template +const SparseInnerVectorSet SparseMatrixBase::middleCols(Index start, Index size) const +{ + EIGEN_STATIC_ASSERT(!IsRowMajor,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); + return innerVectors(start, size); +} + + + +/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this + * is col-major (resp. row-major). + */ +template +SparseInnerVectorSet SparseMatrixBase::innerVectors(Index outerStart, Index outerSize) +{ return SparseInnerVectorSet(derived(), outerStart, outerSize); } + +/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this + * is col-major (resp. row-major). Read-only. + */ +template +const SparseInnerVectorSet SparseMatrixBase::innerVectors(Index outerStart, Index outerSize) const +{ return SparseInnerVectorSet(derived(), outerStart, outerSize); } + +} // end namespace Eigen + +#endif // EIGEN_SPARSE_BLOCK_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h b/extern/Eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h new file mode 100644 index 00000000000..d5f97f78fc9 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h @@ -0,0 +1,324 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSE_CWISE_BINARY_OP_H +#define EIGEN_SPARSE_CWISE_BINARY_OP_H + +namespace Eigen { + +// Here we have to handle 3 cases: +// 1 - sparse op dense +// 2 - dense op sparse +// 3 - sparse op sparse +// We also need to implement a 4th iterator for: +// 4 - dense op dense +// Finally, we also need to distinguish between the product and other operations : +// configuration returned mode +// 1 - sparse op dense product sparse +// generic dense +// 2 - dense op sparse product sparse +// generic dense +// 3 - sparse op sparse product sparse +// generic sparse +// 4 - dense op dense product dense +// generic dense + +namespace internal { + +template<> struct promote_storage_type +{ typedef Sparse ret; }; + +template<> struct promote_storage_type +{ typedef Sparse ret; }; + +template::StorageKind, + typename _RhsStorageMode = typename traits::StorageKind> +class sparse_cwise_binary_op_inner_iterator_selector; + +} // end namespace internal + +template +class CwiseBinaryOpImpl + : public SparseMatrixBase > +{ + public: + class InnerIterator; + class ReverseInnerIterator; + typedef CwiseBinaryOp Derived; + EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) + CwiseBinaryOpImpl() + { + typedef typename internal::traits::StorageKind LhsStorageKind; + typedef typename internal::traits::StorageKind RhsStorageKind; + EIGEN_STATIC_ASSERT(( + (!internal::is_same::value) + || ((Lhs::Flags&RowMajorBit) == (Rhs::Flags&RowMajorBit))), + THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH); + } +}; + +template +class CwiseBinaryOpImpl::InnerIterator + : public internal::sparse_cwise_binary_op_inner_iterator_selector::InnerIterator> +{ + public: + typedef typename Lhs::Index Index; + typedef internal::sparse_cwise_binary_op_inner_iterator_selector< + BinaryOp,Lhs,Rhs, InnerIterator> Base; + + EIGEN_STRONG_INLINE InnerIterator(const CwiseBinaryOpImpl& binOp, typename CwiseBinaryOpImpl::Index outer) + : Base(binOp.derived(),outer) + {} +}; + +/*************************************************************************** +* Implementation of inner-iterators +***************************************************************************/ + +// template struct internal::func_is_conjunction { enum { ret = false }; }; +// template struct internal::func_is_conjunction > { enum { ret = true }; }; + +// TODO generalize the internal::scalar_product_op specialization to all conjunctions if any ! + +namespace internal { + +// sparse - sparse (generic) +template +class sparse_cwise_binary_op_inner_iterator_selector +{ + typedef CwiseBinaryOp CwiseBinaryXpr; + typedef typename traits::Scalar Scalar; + typedef typename traits::_LhsNested _LhsNested; + typedef typename traits::_RhsNested _RhsNested; + typedef typename _LhsNested::InnerIterator LhsIterator; + typedef typename _RhsNested::InnerIterator RhsIterator; + typedef typename Lhs::Index Index; + + public: + + EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) + : m_lhsIter(xpr.lhs(),outer), m_rhsIter(xpr.rhs(),outer), m_functor(xpr.functor()) + { + this->operator++(); + } + + EIGEN_STRONG_INLINE Derived& operator++() + { + if (m_lhsIter && m_rhsIter && (m_lhsIter.index() == m_rhsIter.index())) + { + m_id = m_lhsIter.index(); + m_value = m_functor(m_lhsIter.value(), m_rhsIter.value()); + ++m_lhsIter; + ++m_rhsIter; + } + else if (m_lhsIter && (!m_rhsIter || (m_lhsIter.index() < m_rhsIter.index()))) + { + m_id = m_lhsIter.index(); + m_value = m_functor(m_lhsIter.value(), Scalar(0)); + ++m_lhsIter; + } + else if (m_rhsIter && (!m_lhsIter || (m_lhsIter.index() > m_rhsIter.index()))) + { + m_id = m_rhsIter.index(); + m_value = m_functor(Scalar(0), m_rhsIter.value()); + ++m_rhsIter; + } + else + { + m_value = 0; // this is to avoid a compilation warning + m_id = -1; + } + return *static_cast(this); + } + + EIGEN_STRONG_INLINE Scalar value() const { return m_value; } + + EIGEN_STRONG_INLINE Index index() const { return m_id; } + EIGEN_STRONG_INLINE Index row() const { return Lhs::IsRowMajor ? m_lhsIter.row() : index(); } + EIGEN_STRONG_INLINE Index col() const { return Lhs::IsRowMajor ? index() : m_lhsIter.col(); } + + EIGEN_STRONG_INLINE operator bool() const { return m_id>=0; } + + protected: + LhsIterator m_lhsIter; + RhsIterator m_rhsIter; + const BinaryOp& m_functor; + Scalar m_value; + Index m_id; +}; + +// sparse - sparse (product) +template +class sparse_cwise_binary_op_inner_iterator_selector, Lhs, Rhs, Derived, Sparse, Sparse> +{ + typedef scalar_product_op BinaryFunc; + typedef CwiseBinaryOp CwiseBinaryXpr; + typedef typename CwiseBinaryXpr::Scalar Scalar; + typedef typename traits::_LhsNested _LhsNested; + typedef typename _LhsNested::InnerIterator LhsIterator; + typedef typename traits::_RhsNested _RhsNested; + typedef typename _RhsNested::InnerIterator RhsIterator; + typedef typename Lhs::Index Index; + public: + + EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) + : m_lhsIter(xpr.lhs(),outer), m_rhsIter(xpr.rhs(),outer), m_functor(xpr.functor()) + { + while (m_lhsIter && m_rhsIter && (m_lhsIter.index() != m_rhsIter.index())) + { + if (m_lhsIter.index() < m_rhsIter.index()) + ++m_lhsIter; + else + ++m_rhsIter; + } + } + + EIGEN_STRONG_INLINE Derived& operator++() + { + ++m_lhsIter; + ++m_rhsIter; + while (m_lhsIter && m_rhsIter && (m_lhsIter.index() != m_rhsIter.index())) + { + if (m_lhsIter.index() < m_rhsIter.index()) + ++m_lhsIter; + else + ++m_rhsIter; + } + return *static_cast(this); + } + + EIGEN_STRONG_INLINE Scalar value() const { return m_functor(m_lhsIter.value(), m_rhsIter.value()); } + + EIGEN_STRONG_INLINE Index index() const { return m_lhsIter.index(); } + EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); } + EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); } + + EIGEN_STRONG_INLINE operator bool() const { return (m_lhsIter && m_rhsIter); } + + protected: + LhsIterator m_lhsIter; + RhsIterator m_rhsIter; + const BinaryFunc& m_functor; +}; + +// sparse - dense (product) +template +class sparse_cwise_binary_op_inner_iterator_selector, Lhs, Rhs, Derived, Sparse, Dense> +{ + typedef scalar_product_op BinaryFunc; + typedef CwiseBinaryOp CwiseBinaryXpr; + typedef typename CwiseBinaryXpr::Scalar Scalar; + typedef typename traits::_LhsNested _LhsNested; + typedef typename traits::RhsNested RhsNested; + typedef typename _LhsNested::InnerIterator LhsIterator; + typedef typename Lhs::Index Index; + enum { IsRowMajor = (int(Lhs::Flags)&RowMajorBit)==RowMajorBit }; + public: + + EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) + : m_rhs(xpr.rhs()), m_lhsIter(xpr.lhs(),outer), m_functor(xpr.functor()), m_outer(outer) + {} + + EIGEN_STRONG_INLINE Derived& operator++() + { + ++m_lhsIter; + return *static_cast(this); + } + + EIGEN_STRONG_INLINE Scalar value() const + { return m_functor(m_lhsIter.value(), + m_rhs.coeff(IsRowMajor?m_outer:m_lhsIter.index(),IsRowMajor?m_lhsIter.index():m_outer)); } + + EIGEN_STRONG_INLINE Index index() const { return m_lhsIter.index(); } + EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); } + EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); } + + EIGEN_STRONG_INLINE operator bool() const { return m_lhsIter; } + + protected: + RhsNested m_rhs; + LhsIterator m_lhsIter; + const BinaryFunc m_functor; + const Index m_outer; +}; + +// sparse - dense (product) +template +class sparse_cwise_binary_op_inner_iterator_selector, Lhs, Rhs, Derived, Dense, Sparse> +{ + typedef scalar_product_op BinaryFunc; + typedef CwiseBinaryOp CwiseBinaryXpr; + typedef typename CwiseBinaryXpr::Scalar Scalar; + typedef typename traits::_RhsNested _RhsNested; + typedef typename _RhsNested::InnerIterator RhsIterator; + typedef typename Lhs::Index Index; + + enum { IsRowMajor = (int(Rhs::Flags)&RowMajorBit)==RowMajorBit }; + public: + + EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) + : m_xpr(xpr), m_rhsIter(xpr.rhs(),outer), m_functor(xpr.functor()), m_outer(outer) + {} + + EIGEN_STRONG_INLINE Derived& operator++() + { + ++m_rhsIter; + return *static_cast(this); + } + + EIGEN_STRONG_INLINE Scalar value() const + { return m_functor(m_xpr.lhs().coeff(IsRowMajor?m_outer:m_rhsIter.index(),IsRowMajor?m_rhsIter.index():m_outer), m_rhsIter.value()); } + + EIGEN_STRONG_INLINE Index index() const { return m_rhsIter.index(); } + EIGEN_STRONG_INLINE Index row() const { return m_rhsIter.row(); } + EIGEN_STRONG_INLINE Index col() const { return m_rhsIter.col(); } + + EIGEN_STRONG_INLINE operator bool() const { return m_rhsIter; } + + protected: + const CwiseBinaryXpr& m_xpr; + RhsIterator m_rhsIter; + const BinaryFunc& m_functor; + const Index m_outer; +}; + +} // end namespace internal + +/*************************************************************************** +* Implementation of SparseMatrixBase and SparseCwise functions/operators +***************************************************************************/ + +template +template +EIGEN_STRONG_INLINE Derived & +SparseMatrixBase::operator-=(const SparseMatrixBase &other) +{ + return *this = derived() - other.derived(); +} + +template +template +EIGEN_STRONG_INLINE Derived & +SparseMatrixBase::operator+=(const SparseMatrixBase& other) +{ + return *this = derived() + other.derived(); +} + +template +template +EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE +SparseMatrixBase::cwiseProduct(const MatrixBase &other) const +{ + return EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE(derived(), other.derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_SPARSE_CWISE_BINARY_OP_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseCwiseUnaryOp.h b/extern/Eigen3/Eigen/src/SparseCore/SparseCwiseUnaryOp.h new file mode 100644 index 00000000000..5a50c780303 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseCwiseUnaryOp.h @@ -0,0 +1,163 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSE_CWISE_UNARY_OP_H +#define EIGEN_SPARSE_CWISE_UNARY_OP_H + +namespace Eigen { + +template +class CwiseUnaryOpImpl + : public SparseMatrixBase > +{ + public: + + class InnerIterator; + class ReverseInnerIterator; + + typedef CwiseUnaryOp Derived; + EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) + + protected: + typedef typename internal::traits::_XprTypeNested _MatrixTypeNested; + typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator; + typedef typename _MatrixTypeNested::ReverseInnerIterator MatrixTypeReverseIterator; +}; + +template +class CwiseUnaryOpImpl::InnerIterator + : public CwiseUnaryOpImpl::MatrixTypeIterator +{ + typedef typename CwiseUnaryOpImpl::Scalar Scalar; + typedef typename CwiseUnaryOpImpl::MatrixTypeIterator Base; + public: + + EIGEN_STRONG_INLINE InnerIterator(const CwiseUnaryOpImpl& unaryOp, typename CwiseUnaryOpImpl::Index outer) + : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) + {} + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { Base::operator++(); return *this; } + + EIGEN_STRONG_INLINE typename CwiseUnaryOpImpl::Scalar value() const { return m_functor(Base::value()); } + + protected: + const UnaryOp m_functor; + private: + typename CwiseUnaryOpImpl::Scalar& valueRef(); +}; + +template +class CwiseUnaryOpImpl::ReverseInnerIterator + : public CwiseUnaryOpImpl::MatrixTypeReverseIterator +{ + typedef typename CwiseUnaryOpImpl::Scalar Scalar; + typedef typename CwiseUnaryOpImpl::MatrixTypeReverseIterator Base; + public: + + EIGEN_STRONG_INLINE ReverseInnerIterator(const CwiseUnaryOpImpl& unaryOp, typename CwiseUnaryOpImpl::Index outer) + : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) + {} + + EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() + { Base::operator--(); return *this; } + + EIGEN_STRONG_INLINE typename CwiseUnaryOpImpl::Scalar value() const { return m_functor(Base::value()); } + + protected: + const UnaryOp m_functor; + private: + typename CwiseUnaryOpImpl::Scalar& valueRef(); +}; + +template +class CwiseUnaryViewImpl + : public SparseMatrixBase > +{ + public: + + class InnerIterator; + class ReverseInnerIterator; + + typedef CwiseUnaryView Derived; + EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) + + protected: + typedef typename internal::traits::_MatrixTypeNested _MatrixTypeNested; + typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator; + typedef typename _MatrixTypeNested::ReverseInnerIterator MatrixTypeReverseIterator; +}; + +template +class CwiseUnaryViewImpl::InnerIterator + : public CwiseUnaryViewImpl::MatrixTypeIterator +{ + typedef typename CwiseUnaryViewImpl::Scalar Scalar; + typedef typename CwiseUnaryViewImpl::MatrixTypeIterator Base; + public: + + EIGEN_STRONG_INLINE InnerIterator(const CwiseUnaryViewImpl& unaryOp, typename CwiseUnaryViewImpl::Index outer) + : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) + {} + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { Base::operator++(); return *this; } + + EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar value() const { return m_functor(Base::value()); } + EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar& valueRef() { return m_functor(Base::valueRef()); } + + protected: + const ViewOp m_functor; +}; + +template +class CwiseUnaryViewImpl::ReverseInnerIterator + : public CwiseUnaryViewImpl::MatrixTypeReverseIterator +{ + typedef typename CwiseUnaryViewImpl::Scalar Scalar; + typedef typename CwiseUnaryViewImpl::MatrixTypeReverseIterator Base; + public: + + EIGEN_STRONG_INLINE ReverseInnerIterator(const CwiseUnaryViewImpl& unaryOp, typename CwiseUnaryViewImpl::Index outer) + : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) + {} + + EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() + { Base::operator--(); return *this; } + + EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar value() const { return m_functor(Base::value()); } + EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar& valueRef() { return m_functor(Base::valueRef()); } + + protected: + const ViewOp m_functor; +}; + +template +EIGEN_STRONG_INLINE Derived& +SparseMatrixBase::operator*=(const Scalar& other) +{ + for (Index j=0; j +EIGEN_STRONG_INLINE Derived& +SparseMatrixBase::operator/=(const Scalar& other) +{ + for (Index j=0; j +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSEDENSEPRODUCT_H +#define EIGEN_SPARSEDENSEPRODUCT_H + +namespace Eigen { + +template struct SparseDenseProductReturnType +{ + typedef SparseTimeDenseProduct Type; +}; + +template struct SparseDenseProductReturnType +{ + typedef SparseDenseOuterProduct Type; +}; + +template struct DenseSparseProductReturnType +{ + typedef DenseTimeSparseProduct Type; +}; + +template struct DenseSparseProductReturnType +{ + typedef SparseDenseOuterProduct Type; +}; + +namespace internal { + +template +struct traits > +{ + typedef Sparse StorageKind; + typedef typename scalar_product_traits::Scalar, + typename traits::Scalar>::ReturnType Scalar; + typedef typename Lhs::Index Index; + typedef typename Lhs::Nested LhsNested; + typedef typename Rhs::Nested RhsNested; + typedef typename remove_all::type _LhsNested; + typedef typename remove_all::type _RhsNested; + + enum { + LhsCoeffReadCost = traits<_LhsNested>::CoeffReadCost, + RhsCoeffReadCost = traits<_RhsNested>::CoeffReadCost, + + RowsAtCompileTime = Tr ? int(traits::RowsAtCompileTime) : int(traits::RowsAtCompileTime), + ColsAtCompileTime = Tr ? int(traits::ColsAtCompileTime) : int(traits::ColsAtCompileTime), + MaxRowsAtCompileTime = Tr ? int(traits::MaxRowsAtCompileTime) : int(traits::MaxRowsAtCompileTime), + MaxColsAtCompileTime = Tr ? int(traits::MaxColsAtCompileTime) : int(traits::MaxColsAtCompileTime), + + Flags = Tr ? RowMajorBit : 0, + + CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + NumTraits::MulCost + }; +}; + +} // end namespace internal + +template +class SparseDenseOuterProduct + : public SparseMatrixBase > +{ + public: + + typedef SparseMatrixBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(SparseDenseOuterProduct) + typedef internal::traits Traits; + + private: + + typedef typename Traits::LhsNested LhsNested; + typedef typename Traits::RhsNested RhsNested; + typedef typename Traits::_LhsNested _LhsNested; + typedef typename Traits::_RhsNested _RhsNested; + + public: + + class InnerIterator; + + EIGEN_STRONG_INLINE SparseDenseOuterProduct(const Lhs& lhs, const Rhs& rhs) + : m_lhs(lhs), m_rhs(rhs) + { + EIGEN_STATIC_ASSERT(!Tr,YOU_MADE_A_PROGRAMMING_MISTAKE); + } + + EIGEN_STRONG_INLINE SparseDenseOuterProduct(const Rhs& rhs, const Lhs& lhs) + : m_lhs(lhs), m_rhs(rhs) + { + EIGEN_STATIC_ASSERT(Tr,YOU_MADE_A_PROGRAMMING_MISTAKE); + } + + EIGEN_STRONG_INLINE Index rows() const { return Tr ? m_rhs.rows() : m_lhs.rows(); } + EIGEN_STRONG_INLINE Index cols() const { return Tr ? m_lhs.cols() : m_rhs.cols(); } + + EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; } + EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; } + + protected: + LhsNested m_lhs; + RhsNested m_rhs; +}; + +template +class SparseDenseOuterProduct::InnerIterator : public _LhsNested::InnerIterator +{ + typedef typename _LhsNested::InnerIterator Base; + public: + EIGEN_STRONG_INLINE InnerIterator(const SparseDenseOuterProduct& prod, Index outer) + : Base(prod.lhs(), 0), m_outer(outer), m_factor(prod.rhs().coeff(outer)) + { + } + + inline Index outer() const { return m_outer; } + inline Index row() const { return Transpose ? Base::row() : m_outer; } + inline Index col() const { return Transpose ? m_outer : Base::row(); } + + inline Scalar value() const { return Base::value() * m_factor; } + + protected: + int m_outer; + Scalar m_factor; +}; + +namespace internal { +template +struct traits > + : traits, Lhs, Rhs> > +{ + typedef Dense StorageKind; + typedef MatrixXpr XprKind; +}; + +template +struct sparse_time_dense_product_impl; + +template +struct sparse_time_dense_product_impl +{ + typedef typename internal::remove_all::type Lhs; + typedef typename internal::remove_all::type Rhs; + typedef typename internal::remove_all::type Res; + typedef typename Lhs::Index Index; + typedef typename Lhs::InnerIterator LhsInnerIterator; + static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, typename Res::Scalar alpha) + { + for(Index c=0; c +struct sparse_time_dense_product_impl +{ + typedef typename internal::remove_all::type Lhs; + typedef typename internal::remove_all::type Rhs; + typedef typename internal::remove_all::type Res; + typedef typename Lhs::InnerIterator LhsInnerIterator; + typedef typename Lhs::Index Index; + static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, typename Res::Scalar alpha) + { + for(Index c=0; c +struct sparse_time_dense_product_impl +{ + typedef typename internal::remove_all::type Lhs; + typedef typename internal::remove_all::type Rhs; + typedef typename internal::remove_all::type Res; + typedef typename Lhs::InnerIterator LhsInnerIterator; + typedef typename Lhs::Index Index; + static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, typename Res::Scalar alpha) + { + for(Index j=0; j +struct sparse_time_dense_product_impl +{ + typedef typename internal::remove_all::type Lhs; + typedef typename internal::remove_all::type Rhs; + typedef typename internal::remove_all::type Res; + typedef typename Lhs::InnerIterator LhsInnerIterator; + typedef typename Lhs::Index Index; + static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, typename Res::Scalar alpha) + { + for(Index j=0; j +inline void sparse_time_dense_product(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const AlphaType& alpha) +{ + sparse_time_dense_product_impl::run(lhs, rhs, res, alpha); +} + +} // end namespace internal + +template +class SparseTimeDenseProduct + : public ProductBase, Lhs, Rhs> +{ + public: + EIGEN_PRODUCT_PUBLIC_INTERFACE(SparseTimeDenseProduct) + + SparseTimeDenseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) + {} + + template void scaleAndAddTo(Dest& dest, Scalar alpha) const + { + internal::sparse_time_dense_product(m_lhs, m_rhs, dest, alpha); + } + + private: + SparseTimeDenseProduct& operator=(const SparseTimeDenseProduct&); +}; + + +// dense = dense * sparse +namespace internal { +template +struct traits > + : traits, Lhs, Rhs> > +{ + typedef Dense StorageKind; +}; +} // end namespace internal + +template +class DenseTimeSparseProduct + : public ProductBase, Lhs, Rhs> +{ + public: + EIGEN_PRODUCT_PUBLIC_INTERFACE(DenseTimeSparseProduct) + + DenseTimeSparseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) + {} + + template void scaleAndAddTo(Dest& dest, Scalar alpha) const + { + Transpose lhs_t(m_lhs); + Transpose rhs_t(m_rhs); + Transpose dest_t(dest); + internal::sparse_time_dense_product(rhs_t, lhs_t, dest_t, alpha); + } + + private: + DenseTimeSparseProduct& operator=(const DenseTimeSparseProduct&); +}; + +// sparse * dense +template +template +inline const typename SparseDenseProductReturnType::Type +SparseMatrixBase::operator*(const MatrixBase &other) const +{ + return typename SparseDenseProductReturnType::Type(derived(), other.derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_SPARSEDENSEPRODUCT_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseDiagonalProduct.h b/extern/Eigen3/Eigen/src/SparseCore/SparseDiagonalProduct.h new file mode 100644 index 00000000000..095bf6863fc --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseDiagonalProduct.h @@ -0,0 +1,184 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSE_DIAGONAL_PRODUCT_H +#define EIGEN_SPARSE_DIAGONAL_PRODUCT_H + +namespace Eigen { + +// The product of a diagonal matrix with a sparse matrix can be easily +// implemented using expression template. +// We have two consider very different cases: +// 1 - diag * row-major sparse +// => each inner vector <=> scalar * sparse vector product +// => so we can reuse CwiseUnaryOp::InnerIterator +// 2 - diag * col-major sparse +// => each inner vector <=> densevector * sparse vector cwise product +// => again, we can reuse specialization of CwiseBinaryOp::InnerIterator +// for that particular case +// The two other cases are symmetric. + +namespace internal { + +template +struct traits > +{ + typedef typename remove_all::type _Lhs; + typedef typename remove_all::type _Rhs; + typedef typename _Lhs::Scalar Scalar; + typedef typename promote_index_type::Index, + typename traits::Index>::type Index; + typedef Sparse StorageKind; + typedef MatrixXpr XprKind; + enum { + RowsAtCompileTime = _Lhs::RowsAtCompileTime, + ColsAtCompileTime = _Rhs::ColsAtCompileTime, + + MaxRowsAtCompileTime = _Lhs::MaxRowsAtCompileTime, + MaxColsAtCompileTime = _Rhs::MaxColsAtCompileTime, + + SparseFlags = is_diagonal<_Lhs>::ret ? int(_Rhs::Flags) : int(_Lhs::Flags), + Flags = (SparseFlags&RowMajorBit), + CoeffReadCost = Dynamic + }; +}; + +enum {SDP_IsDiagonal, SDP_IsSparseRowMajor, SDP_IsSparseColMajor}; +template +class sparse_diagonal_product_inner_iterator_selector; + +} // end namespace internal + +template +class SparseDiagonalProduct + : public SparseMatrixBase >, + internal::no_assignment_operator +{ + typedef typename Lhs::Nested LhsNested; + typedef typename Rhs::Nested RhsNested; + + typedef typename internal::remove_all::type _LhsNested; + typedef typename internal::remove_all::type _RhsNested; + + enum { + LhsMode = internal::is_diagonal<_LhsNested>::ret ? internal::SDP_IsDiagonal + : (_LhsNested::Flags&RowMajorBit) ? internal::SDP_IsSparseRowMajor : internal::SDP_IsSparseColMajor, + RhsMode = internal::is_diagonal<_RhsNested>::ret ? internal::SDP_IsDiagonal + : (_RhsNested::Flags&RowMajorBit) ? internal::SDP_IsSparseRowMajor : internal::SDP_IsSparseColMajor + }; + + public: + + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseDiagonalProduct) + + typedef internal::sparse_diagonal_product_inner_iterator_selector + <_LhsNested,_RhsNested,SparseDiagonalProduct,LhsMode,RhsMode> InnerIterator; + + EIGEN_STRONG_INLINE SparseDiagonalProduct(const Lhs& lhs, const Rhs& rhs) + : m_lhs(lhs), m_rhs(rhs) + { + eigen_assert(lhs.cols() == rhs.rows() && "invalid sparse matrix * diagonal matrix product"); + } + + EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); } + EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); } + + EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; } + EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; } + + protected: + LhsNested m_lhs; + RhsNested m_rhs; +}; + +namespace internal { + +template +class sparse_diagonal_product_inner_iterator_selector + + : public CwiseUnaryOp,const Rhs>::InnerIterator +{ + typedef typename CwiseUnaryOp,const Rhs>::InnerIterator Base; + typedef typename Lhs::Index Index; + public: + inline sparse_diagonal_product_inner_iterator_selector( + const SparseDiagonalProductType& expr, Index outer) + : Base(expr.rhs()*(expr.lhs().diagonal().coeff(outer)), outer) + {} +}; + +template +class sparse_diagonal_product_inner_iterator_selector + + : public CwiseBinaryOp< + scalar_product_op, + SparseInnerVectorSet, + typename Lhs::DiagonalVectorType>::InnerIterator +{ + typedef typename CwiseBinaryOp< + scalar_product_op, + SparseInnerVectorSet, + typename Lhs::DiagonalVectorType>::InnerIterator Base; + typedef typename Lhs::Index Index; + public: + inline sparse_diagonal_product_inner_iterator_selector( + const SparseDiagonalProductType& expr, Index outer) + : Base(expr.rhs().innerVector(outer) .cwiseProduct(expr.lhs().diagonal()), 0) + {} +}; + +template +class sparse_diagonal_product_inner_iterator_selector + + : public CwiseUnaryOp,const Lhs>::InnerIterator +{ + typedef typename CwiseUnaryOp,const Lhs>::InnerIterator Base; + typedef typename Lhs::Index Index; + public: + inline sparse_diagonal_product_inner_iterator_selector( + const SparseDiagonalProductType& expr, Index outer) + : Base(expr.lhs()*expr.rhs().diagonal().coeff(outer), outer) + {} +}; + +template +class sparse_diagonal_product_inner_iterator_selector + + : public CwiseBinaryOp< + scalar_product_op, + SparseInnerVectorSet, + Transpose >::InnerIterator +{ + typedef typename CwiseBinaryOp< + scalar_product_op, + SparseInnerVectorSet, + Transpose >::InnerIterator Base; + typedef typename Lhs::Index Index; + public: + inline sparse_diagonal_product_inner_iterator_selector( + const SparseDiagonalProductType& expr, Index outer) + : Base(expr.lhs().innerVector(outer) .cwiseProduct(expr.rhs().diagonal().transpose()), 0) + {} +}; + +} // end namespace internal + +// SparseMatrixBase functions + +template +template +const SparseDiagonalProduct +SparseMatrixBase::operator*(const DiagonalBase &other) const +{ + return SparseDiagonalProduct(this->derived(), other.derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_SPARSE_DIAGONAL_PRODUCT_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseDot.h b/extern/Eigen3/Eigen/src/SparseCore/SparseDot.h new file mode 100644 index 00000000000..5c4a593dc01 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseDot.h @@ -0,0 +1,94 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSE_DOT_H +#define EIGEN_SPARSE_DOT_H + +namespace Eigen { + +template +template +typename internal::traits::Scalar +SparseMatrixBase::dot(const MatrixBase& other) const +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) + EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) + EIGEN_STATIC_ASSERT((internal::is_same::value), + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + + eigen_assert(size() == other.size()); + eigen_assert(other.size()>0 && "you are using a non initialized vector"); + + typename Derived::InnerIterator i(derived(),0); + Scalar res(0); + while (i) + { + res += internal::conj(i.value()) * other.coeff(i.index()); + ++i; + } + return res; +} + +template +template +typename internal::traits::Scalar +SparseMatrixBase::dot(const SparseMatrixBase& other) const +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) + EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) + EIGEN_STATIC_ASSERT((internal::is_same::value), + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + + eigen_assert(size() == other.size()); + + typedef typename Derived::Nested Nested; + typedef typename OtherDerived::Nested OtherNested; + typedef typename internal::remove_all::type NestedCleaned; + typedef typename internal::remove_all::type OtherNestedCleaned; + + const Nested nthis(derived()); + const OtherNested nother(other.derived()); + + typename NestedCleaned::InnerIterator i(nthis,0); + typename OtherNestedCleaned::InnerIterator j(nother,0); + Scalar res(0); + while (i && j) + { + if (i.index()==j.index()) + { + res += internal::conj(i.value()) * j.value(); + ++i; ++j; + } + else if (i.index() +inline typename NumTraits::Scalar>::Real +SparseMatrixBase::squaredNorm() const +{ + return internal::real((*this).cwiseAbs2().sum()); +} + +template +inline typename NumTraits::Scalar>::Real +SparseMatrixBase::norm() const +{ + return internal::sqrt(squaredNorm()); +} + +} // end namespace Eigen + +#endif // EIGEN_SPARSE_DOT_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseFuzzy.h b/extern/Eigen3/Eigen/src/SparseCore/SparseFuzzy.h new file mode 100644 index 00000000000..45f36e9eb90 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseFuzzy.h @@ -0,0 +1,26 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSE_FUZZY_H +#define EIGEN_SPARSE_FUZZY_H + +// template +// template +// bool SparseMatrixBase::isApprox( +// const OtherDerived& other, +// typename NumTraits::Real prec +// ) const +// { +// const typename internal::nested::type nested(derived()); +// const typename internal::nested::type otherNested(other.derived()); +// return (nested - otherNested).cwise().abs2().sum() +// <= prec * prec * (std::min)(nested.cwise().abs2().sum(), otherNested.cwise().abs2().sum()); +// } + +#endif // EIGEN_SPARSE_FUZZY_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseMatrix.h b/extern/Eigen3/Eigen/src/SparseCore/SparseMatrix.h new file mode 100644 index 00000000000..efb774f031b --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseMatrix.h @@ -0,0 +1,1116 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSEMATRIX_H +#define EIGEN_SPARSEMATRIX_H + +namespace Eigen { + +/** \ingroup SparseCore_Module + * + * \class SparseMatrix + * + * \brief A versatible sparse matrix representation + * + * This class implements a more versatile variants of the common \em compressed row/column storage format. + * Each colmun's (resp. row) non zeros are stored as a pair of value with associated row (resp. colmiun) index. + * All the non zeros are stored in a single large buffer. Unlike the \em compressed format, there might be extra + * space inbetween the nonzeros of two successive colmuns (resp. rows) such that insertion of new non-zero + * can be done with limited memory reallocation and copies. + * + * A call to the function makeCompressed() turns the matrix into the standard \em compressed format + * compatible with many library. + * + * More details on this storage sceheme are given in the \ref TutorialSparse "manual pages". + * + * \tparam _Scalar the scalar type, i.e. the type of the coefficients + * \tparam _Options Union of bit flags controlling the storage scheme. Currently the only possibility + * is RowMajor. The default is 0 which means column-major. + * \tparam _Index the type of the indices. It has to be a \b signed type (e.g., short, int, std::ptrdiff_t). Default is \c int. + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEMATRIX_PLUGIN. + */ + +namespace internal { +template +struct traits > +{ + typedef _Scalar Scalar; + typedef _Index Index; + typedef Sparse StorageKind; + typedef MatrixXpr XprKind; + enum { + RowsAtCompileTime = Dynamic, + ColsAtCompileTime = Dynamic, + MaxRowsAtCompileTime = Dynamic, + MaxColsAtCompileTime = Dynamic, + Flags = _Options | NestByRefBit | LvalueBit, + CoeffReadCost = NumTraits::ReadCost, + SupportedAccessPatterns = InnerRandomAccessPattern + }; +}; + +template +struct traits, DiagIndex> > +{ + typedef SparseMatrix<_Scalar, _Options, _Index> MatrixType; + typedef typename nested::type MatrixTypeNested; + typedef typename remove_reference::type _MatrixTypeNested; + + typedef _Scalar Scalar; + typedef Dense StorageKind; + typedef _Index Index; + typedef MatrixXpr XprKind; + + enum { + RowsAtCompileTime = Dynamic, + ColsAtCompileTime = 1, + MaxRowsAtCompileTime = Dynamic, + MaxColsAtCompileTime = 1, + Flags = 0, + CoeffReadCost = _MatrixTypeNested::CoeffReadCost*10 + }; +}; + +} // end namespace internal + +template +class SparseMatrix + : public SparseMatrixBase > +{ + public: + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseMatrix) + EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseMatrix, +=) + EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseMatrix, -=) + + typedef MappedSparseMatrix Map; + using Base::IsRowMajor; + typedef internal::CompressedStorage Storage; + enum { + Options = _Options + }; + + protected: + + typedef SparseMatrix TransposedSparseMatrix; + + Index m_outerSize; + Index m_innerSize; + Index* m_outerIndex; + Index* m_innerNonZeros; // optional, if null then the data is compressed + Storage m_data; + + Eigen::Map > innerNonZeros() { return Eigen::Map >(m_innerNonZeros, m_innerNonZeros?m_outerSize:0); } + const Eigen::Map > innerNonZeros() const { return Eigen::Map >(m_innerNonZeros, m_innerNonZeros?m_outerSize:0); } + + public: + + /** \returns whether \c *this is in compressed form. */ + inline bool isCompressed() const { return m_innerNonZeros==0; } + + /** \returns the number of rows of the matrix */ + inline Index rows() const { return IsRowMajor ? m_outerSize : m_innerSize; } + /** \returns the number of columns of the matrix */ + inline Index cols() const { return IsRowMajor ? m_innerSize : m_outerSize; } + + /** \returns the number of rows (resp. columns) of the matrix if the storage order column major (resp. row major) */ + inline Index innerSize() const { return m_innerSize; } + /** \returns the number of columns (resp. rows) of the matrix if the storage order column major (resp. row major) */ + inline Index outerSize() const { return m_outerSize; } + + /** \returns a const pointer to the array of values. + * This function is aimed at interoperability with other libraries. + * \sa innerIndexPtr(), outerIndexPtr() */ + inline const Scalar* valuePtr() const { return &m_data.value(0); } + /** \returns a non-const pointer to the array of values. + * This function is aimed at interoperability with other libraries. + * \sa innerIndexPtr(), outerIndexPtr() */ + inline Scalar* valuePtr() { return &m_data.value(0); } + + /** \returns a const pointer to the array of inner indices. + * This function is aimed at interoperability with other libraries. + * \sa valuePtr(), outerIndexPtr() */ + inline const Index* innerIndexPtr() const { return &m_data.index(0); } + /** \returns a non-const pointer to the array of inner indices. + * This function is aimed at interoperability with other libraries. + * \sa valuePtr(), outerIndexPtr() */ + inline Index* innerIndexPtr() { return &m_data.index(0); } + + /** \returns a const pointer to the array of the starting positions of the inner vectors. + * This function is aimed at interoperability with other libraries. + * \sa valuePtr(), innerIndexPtr() */ + inline const Index* outerIndexPtr() const { return m_outerIndex; } + /** \returns a non-const pointer to the array of the starting positions of the inner vectors. + * This function is aimed at interoperability with other libraries. + * \sa valuePtr(), innerIndexPtr() */ + inline Index* outerIndexPtr() { return m_outerIndex; } + + /** \returns a const pointer to the array of the number of non zeros of the inner vectors. + * This function is aimed at interoperability with other libraries. + * \warning it returns the null pointer 0 in compressed mode */ + inline const Index* innerNonZeroPtr() const { return m_innerNonZeros; } + /** \returns a non-const pointer to the array of the number of non zeros of the inner vectors. + * This function is aimed at interoperability with other libraries. + * \warning it returns the null pointer 0 in compressed mode */ + inline Index* innerNonZeroPtr() { return m_innerNonZeros; } + + /** \internal */ + inline Storage& data() { return m_data; } + /** \internal */ + inline const Storage& data() const { return m_data; } + + /** \returns the value of the matrix at position \a i, \a j + * This function returns Scalar(0) if the element is an explicit \em zero */ + inline Scalar coeff(Index row, Index col) const + { + const Index outer = IsRowMajor ? row : col; + const Index inner = IsRowMajor ? col : row; + Index end = m_innerNonZeros ? m_outerIndex[outer] + m_innerNonZeros[outer] : m_outerIndex[outer+1]; + return m_data.atInRange(m_outerIndex[outer], end, inner); + } + + /** \returns a non-const reference to the value of the matrix at position \a i, \a j + * + * If the element does not exist then it is inserted via the insert(Index,Index) function + * which itself turns the matrix into a non compressed form if that was not the case. + * + * This is a O(log(nnz_j)) operation (binary search) plus the cost of insert(Index,Index) + * function if the element does not already exist. + */ + inline Scalar& coeffRef(Index row, Index col) + { + const Index outer = IsRowMajor ? row : col; + const Index inner = IsRowMajor ? col : row; + + Index start = m_outerIndex[outer]; + Index end = m_innerNonZeros ? m_outerIndex[outer] + m_innerNonZeros[outer] : m_outerIndex[outer+1]; + eigen_assert(end>=start && "you probably called coeffRef on a non finalized matrix"); + if(end<=start) + return insert(row,col); + const Index p = m_data.searchLowerIndex(start,end-1,inner); + if((p(m_data.size()); + } + + /** Preallocates \a reserveSize non zeros. + * + * Precondition: the matrix must be in compressed mode. */ + inline void reserve(Index reserveSize) + { + eigen_assert(isCompressed() && "This function does not make sense in non compressed mode."); + m_data.reserve(reserveSize); + } + + #ifdef EIGEN_PARSED_BY_DOXYGEN + /** Preallocates \a reserveSize[\c j] non zeros for each column (resp. row) \c j. + * + * This function turns the matrix in non-compressed mode */ + template + inline void reserve(const SizesType& reserveSizes); + #else + template + inline void reserve(const SizesType& reserveSizes, const typename SizesType::value_type& enableif = typename SizesType::value_type()) + { + EIGEN_UNUSED_VARIABLE(enableif); + reserveInnerVectors(reserveSizes); + } + template + inline void reserve(const SizesType& reserveSizes, const typename SizesType::Scalar& enableif = + #if (!defined(_MSC_VER)) || (_MSC_VER>=1500) // MSVC 2005 fails to compile with this typename + typename + #endif + SizesType::Scalar()) + { + EIGEN_UNUSED_VARIABLE(enableif); + reserveInnerVectors(reserveSizes); + } + #endif // EIGEN_PARSED_BY_DOXYGEN + protected: + template + inline void reserveInnerVectors(const SizesType& reserveSizes) + { + + if(isCompressed()) + { + std::size_t totalReserveSize = 0; + // turn the matrix into non-compressed mode + m_innerNonZeros = new Index[m_outerSize]; + + // temporarily use m_innerSizes to hold the new starting points. + Index* newOuterIndex = m_innerNonZeros; + + Index count = 0; + for(Index j=0; j=0; --j) + { + ptrdiff_t innerNNZ = previousOuterIndex - m_outerIndex[j]; + for(std::ptrdiff_t i=innerNNZ-1; i>=0; --i) + { + m_data.index(newOuterIndex[j]+i) = m_data.index(m_outerIndex[j]+i); + m_data.value(newOuterIndex[j]+i) = m_data.value(m_outerIndex[j]+i); + } + previousOuterIndex = m_outerIndex[j]; + m_outerIndex[j] = newOuterIndex[j]; + m_innerNonZeros[j] = innerNNZ; + } + m_outerIndex[m_outerSize] = m_outerIndex[m_outerSize-1] + m_innerNonZeros[m_outerSize-1] + reserveSizes[m_outerSize-1]; + + m_data.resize(m_outerIndex[m_outerSize]); + } + else + { + Index* newOuterIndex = new Index[m_outerSize+1]; + Index count = 0; + for(Index j=0; j(reserveSizes[j], alreadyReserved); + count += toReserve + m_innerNonZeros[j]; + } + newOuterIndex[m_outerSize] = count; + + m_data.resize(count); + for(ptrdiff_t j=m_outerSize-1; j>=0; --j) + { + std::ptrdiff_t offset = newOuterIndex[j] - m_outerIndex[j]; + if(offset>0) + { + std::ptrdiff_t innerNNZ = m_innerNonZeros[j]; + for(std::ptrdiff_t i=innerNNZ-1; i>=0; --i) + { + m_data.index(newOuterIndex[j]+i) = m_data.index(m_outerIndex[j]+i); + m_data.value(newOuterIndex[j]+i) = m_data.value(m_outerIndex[j]+i); + } + } + } + + std::swap(m_outerIndex, newOuterIndex); + delete[] newOuterIndex; + } + + } + public: + + //--- low level purely coherent filling --- + + /** \internal + * \returns a reference to the non zero coefficient at position \a row, \a col assuming that: + * - the nonzero does not already exist + * - the new coefficient is the last one according to the storage order + * + * Before filling a given inner vector you must call the statVec(Index) function. + * + * After an insertion session, you should call the finalize() function. + * + * \sa insert, insertBackByOuterInner, startVec */ + inline Scalar& insertBack(Index row, Index col) + { + return insertBackByOuterInner(IsRowMajor?row:col, IsRowMajor?col:row); + } + + /** \internal + * \sa insertBack, startVec */ + inline Scalar& insertBackByOuterInner(Index outer, Index inner) + { + eigen_assert(size_t(m_outerIndex[outer+1]) == m_data.size() && "Invalid ordered insertion (invalid outer index)"); + eigen_assert( (m_outerIndex[outer+1]-m_outerIndex[outer]==0 || m_data.index(m_data.size()-1)(m_data.size()); + Index i = m_outerSize; + // find the last filled column + while (i>=0 && m_outerIndex[i]==0) + --i; + ++i; + while (i<=m_outerSize) + { + m_outerIndex[i] = size; + ++i; + } + } + } + + //--- + + template + void setFromTriplets(const InputIterators& begin, const InputIterators& end); + + void sumupDuplicates(); + + //--- + + /** \internal + * same as insert(Index,Index) except that the indices are given relative to the storage order */ + EIGEN_DONT_INLINE Scalar& insertByOuterInner(Index j, Index i) + { + return insert(IsRowMajor ? j : i, IsRowMajor ? i : j); + } + + /** Turns the matrix into the \em compressed format. + */ + void makeCompressed() + { + if(isCompressed()) + return; + + Index oldStart = m_outerIndex[1]; + m_outerIndex[1] = m_innerNonZeros[0]; + for(Index j=1; j0) + { + for(Index k=0; k::dummy_precision()) + { + prune(default_prunning_func(reference,epsilon)); + } + + /** Turns the matrix into compressed format, and suppresses all nonzeros which do not satisfy the predicate \a keep. + * The functor type \a KeepFunc must implement the following function: + * \code + * bool operator() (const Index& row, const Index& col, const Scalar& value) const; + * \endcode + * \sa prune(Scalar,RealScalar) + */ + template + void prune(const KeepFunc& keep = KeepFunc()) + { + // TODO optimize the uncompressed mode to avoid moving and allocating the data twice + // TODO also implement a unit test + makeCompressed(); + + Index k = 0; + for(Index j=0; j diagonal() const { return *this; } + + /** Default constructor yielding an empty \c 0 \c x \c 0 matrix */ + inline SparseMatrix() + : m_outerSize(-1), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) + { + check_template_parameters(); + resize(0, 0); + } + + /** Constructs a \a rows \c x \a cols empty matrix */ + inline SparseMatrix(Index rows, Index cols) + : m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) + { + check_template_parameters(); + resize(rows, cols); + } + + /** Constructs a sparse matrix from the sparse expression \a other */ + template + inline SparseMatrix(const SparseMatrixBase& other) + : m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) + { + check_template_parameters(); + *this = other.derived(); + } + + /** Copy constructor (it performs a deep copy) */ + inline SparseMatrix(const SparseMatrix& other) + : Base(), m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) + { + check_template_parameters(); + *this = other.derived(); + } + + /** Swaps the content of two sparse matrices of the same type. + * This is a fast operation that simply swaps the underlying pointers and parameters. */ + inline void swap(SparseMatrix& other) + { + //EIGEN_DBG_SPARSE(std::cout << "SparseMatrix:: swap\n"); + std::swap(m_outerIndex, other.m_outerIndex); + std::swap(m_innerSize, other.m_innerSize); + std::swap(m_outerSize, other.m_outerSize); + std::swap(m_innerNonZeros, other.m_innerNonZeros); + m_data.swap(other.m_data); + } + + inline SparseMatrix& operator=(const SparseMatrix& other) + { + if (other.isRValue()) + { + swap(other.const_cast_derived()); + } + else + { + initAssignment(other); + if(other.isCompressed()) + { + memcpy(m_outerIndex, other.m_outerIndex, (m_outerSize+1)*sizeof(Index)); + m_data = other.m_data; + } + else + { + Base::operator=(other); + } + } + return *this; + } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + inline SparseMatrix& operator=(const SparseSparseProduct& product) + { return Base::operator=(product); } + + template + inline SparseMatrix& operator=(const ReturnByValue& other) + { return Base::operator=(other.derived()); } + + template + inline SparseMatrix& operator=(const EigenBase& other) + { return Base::operator=(other.derived()); } + #endif + + template + EIGEN_DONT_INLINE SparseMatrix& operator=(const SparseMatrixBase& other) + { + initAssignment(other.derived()); + const bool needToTranspose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); + if (needToTranspose) + { + // two passes algorithm: + // 1 - compute the number of coeffs per dest inner vector + // 2 - do the actual copy/eval + // Since each coeff of the rhs has to be evaluated twice, let's evaluate it if needed + typedef typename internal::nested::type OtherCopy; + typedef typename internal::remove_all::type _OtherCopy; + OtherCopy otherCopy(other.derived()); + + Eigen::Map > (m_outerIndex,outerSize()).setZero(); + // pass 1 + // FIXME the above copy could be merged with that pass + for (Index j=0; j&>(m); + return s; + } + + /** Destructor */ + inline ~SparseMatrix() + { + delete[] m_outerIndex; + delete[] m_innerNonZeros; + } + +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** Overloaded for performance */ + Scalar sum() const; +#endif + +# ifdef EIGEN_SPARSEMATRIX_PLUGIN +# include EIGEN_SPARSEMATRIX_PLUGIN +# endif + +protected: + + template + void initAssignment(const Other& other) + { + resize(other.rows(), other.cols()); + if(m_innerNonZeros) + { + delete[] m_innerNonZeros; + m_innerNonZeros = 0; + } + } + + /** \internal + * \sa insert(Index,Index) */ + EIGEN_DONT_INLINE Scalar& insertCompressed(Index row, Index col) + { + eigen_assert(isCompressed()); + + const Index outer = IsRowMajor ? row : col; + const Index inner = IsRowMajor ? col : row; + + Index previousOuter = outer; + if (m_outerIndex[outer+1]==0) + { + // we start a new inner vector + while (previousOuter>=0 && m_outerIndex[previousOuter]==0) + { + m_outerIndex[previousOuter] = static_cast(m_data.size()); + --previousOuter; + } + m_outerIndex[outer+1] = m_outerIndex[outer]; + } + + // here we have to handle the tricky case where the outerIndex array + // starts with: [ 0 0 0 0 0 1 ...] and we are inserted in, e.g., + // the 2nd inner vector... + bool isLastVec = (!(previousOuter==-1 && m_data.size()!=0)) + && (size_t(m_outerIndex[outer+1]) == m_data.size()); + + size_t startId = m_outerIndex[outer]; + // FIXME let's make sure sizeof(long int) == sizeof(size_t) + size_t p = m_outerIndex[outer+1]; + ++m_outerIndex[outer+1]; + + float reallocRatio = 1; + if (m_data.allocatedSize()<=m_data.size()) + { + // if there is no preallocated memory, let's reserve a minimum of 32 elements + if (m_data.size()==0) + { + m_data.reserve(32); + } + else + { + // we need to reallocate the data, to reduce multiple reallocations + // we use a smart resize algorithm based on the current filling ratio + // in addition, we use float to avoid integers overflows + float nnzEstimate = float(m_outerIndex[outer])*float(m_outerSize)/float(outer+1); + reallocRatio = (nnzEstimate-float(m_data.size()))/float(m_data.size()); + // furthermore we bound the realloc ratio to: + // 1) reduce multiple minor realloc when the matrix is almost filled + // 2) avoid to allocate too much memory when the matrix is almost empty + reallocRatio = (std::min)((std::max)(reallocRatio,1.5f),8.f); + } + } + m_data.resize(m_data.size()+1,reallocRatio); + + if (!isLastVec) + { + if (previousOuter==-1) + { + // oops wrong guess. + // let's correct the outer offsets + for (Index k=0; k<=(outer+1); ++k) + m_outerIndex[k] = 0; + Index k=outer+1; + while(m_outerIndex[k]==0) + m_outerIndex[k++] = 1; + while (k<=m_outerSize && m_outerIndex[k]!=0) + m_outerIndex[k++]++; + p = 0; + --k; + k = m_outerIndex[k]-1; + while (k>0) + { + m_data.index(k) = m_data.index(k-1); + m_data.value(k) = m_data.value(k-1); + k--; + } + } + else + { + // we are not inserting into the last inner vec + // update outer indices: + Index j = outer+2; + while (j<=m_outerSize && m_outerIndex[j]!=0) + m_outerIndex[j++]++; + --j; + // shift data of last vecs: + Index k = m_outerIndex[j]-1; + while (k>=Index(p)) + { + m_data.index(k) = m_data.index(k-1); + m_data.value(k) = m_data.value(k-1); + k--; + } + } + } + + while ( (p > startId) && (m_data.index(p-1) > inner) ) + { + m_data.index(p) = m_data.index(p-1); + m_data.value(p) = m_data.value(p-1); + --p; + } + + m_data.index(p) = inner; + return (m_data.value(p) = 0); + } + + /** \internal + * A vector object that is equal to 0 everywhere but v at the position i */ + class SingletonVector + { + Index m_index; + Index m_value; + public: + typedef Index value_type; + SingletonVector(Index i, Index v) + : m_index(i), m_value(v) + {} + + Index operator[](Index i) const { return i==m_index ? m_value : 0; } + }; + + /** \internal + * \sa insert(Index,Index) */ + EIGEN_DONT_INLINE Scalar& insertUncompressed(Index row, Index col) + { + eigen_assert(!isCompressed()); + + const Index outer = IsRowMajor ? row : col; + const Index inner = IsRowMajor ? col : row; + + std::ptrdiff_t room = m_outerIndex[outer+1] - m_outerIndex[outer]; + std::ptrdiff_t innerNNZ = m_innerNonZeros[outer]; + if(innerNNZ>=room) + { + // this inner vector is full, we need to reallocate the whole buffer :( + reserve(SingletonVector(outer,std::max(2,innerNNZ))); + } + + Index startId = m_outerIndex[outer]; + Index p = startId + m_innerNonZeros[outer]; + while ( (p > startId) && (m_data.index(p-1) > inner) ) + { + m_data.index(p) = m_data.index(p-1); + m_data.value(p) = m_data.value(p-1); + --p; + } + + m_innerNonZeros[outer]++; + + m_data.index(p) = inner; + return (m_data.value(p) = 0); + } + +public: + /** \internal + * \sa insert(Index,Index) */ + inline Scalar& insertBackUncompressed(Index row, Index col) + { + const Index outer = IsRowMajor ? row : col; + const Index inner = IsRowMajor ? col : row; + + eigen_assert(!isCompressed()); + eigen_assert(m_innerNonZeros[outer]<=(m_outerIndex[outer+1] - m_outerIndex[outer])); + + Index p = m_outerIndex[outer] + m_innerNonZeros[outer]; + m_innerNonZeros[outer]++; + m_data.index(p) = inner; + return (m_data.value(p) = 0); + } + +private: + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT(NumTraits::IsSigned,THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE); + } + + struct default_prunning_func { + default_prunning_func(Scalar ref, RealScalar eps) : reference(ref), epsilon(eps) {} + inline bool operator() (const Index&, const Index&, const Scalar& value) const + { + return !internal::isMuchSmallerThan(value, reference, epsilon); + } + Scalar reference; + RealScalar epsilon; + }; +}; + +template +class SparseMatrix::InnerIterator +{ + public: + InnerIterator(const SparseMatrix& mat, Index outer) + : m_values(mat.valuePtr()), m_indices(mat.innerIndexPtr()), m_outer(outer), m_id(mat.m_outerIndex[outer]) + { + if(mat.isCompressed()) + m_end = mat.m_outerIndex[outer+1]; + else + m_end = m_id + mat.m_innerNonZeros[outer]; + } + + inline InnerIterator& operator++() { m_id++; return *this; } + + inline const Scalar& value() const { return m_values[m_id]; } + inline Scalar& valueRef() { return const_cast(m_values[m_id]); } + + inline Index index() const { return m_indices[m_id]; } + inline Index outer() const { return m_outer; } + inline Index row() const { return IsRowMajor ? m_outer : index(); } + inline Index col() const { return IsRowMajor ? index() : m_outer; } + + inline operator bool() const { return (m_id < m_end); } + + protected: + const Scalar* m_values; + const Index* m_indices; + const Index m_outer; + Index m_id; + Index m_end; +}; + +template +class SparseMatrix::ReverseInnerIterator +{ + public: + ReverseInnerIterator(const SparseMatrix& mat, Index outer) + : m_values(mat.valuePtr()), m_indices(mat.innerIndexPtr()), m_outer(outer), m_start(mat.m_outerIndex[outer]) + { + if(mat.isCompressed()) + m_id = mat.m_outerIndex[outer+1]; + else + m_id = m_start + mat.m_innerNonZeros[outer]; + } + + inline ReverseInnerIterator& operator--() { --m_id; return *this; } + + inline const Scalar& value() const { return m_values[m_id-1]; } + inline Scalar& valueRef() { return const_cast(m_values[m_id-1]); } + + inline Index index() const { return m_indices[m_id-1]; } + inline Index outer() const { return m_outer; } + inline Index row() const { return IsRowMajor ? m_outer : index(); } + inline Index col() const { return IsRowMajor ? index() : m_outer; } + + inline operator bool() const { return (m_id > m_start); } + + protected: + const Scalar* m_values; + const Index* m_indices; + const Index m_outer; + Index m_id; + const Index m_start; +}; + +namespace internal { + +template +void set_from_triplets(const InputIterator& begin, const InputIterator& end, SparseMatrixType& mat, int Options = 0) +{ + EIGEN_UNUSED_VARIABLE(Options); + enum { IsRowMajor = SparseMatrixType::IsRowMajor }; + typedef typename SparseMatrixType::Scalar Scalar; + typedef typename SparseMatrixType::Index Index; + SparseMatrix trMat(mat.rows(),mat.cols()); + + // pass 1: count the nnz per inner-vector + VectorXi wi(trMat.outerSize()); + wi.setZero(); + for(InputIterator it(begin); it!=end; ++it) + wi(IsRowMajor ? it->col() : it->row())++; + + // pass 2: insert all the elements into trMat + trMat.reserve(wi); + for(InputIterator it(begin); it!=end; ++it) + trMat.insertBackUncompressed(it->row(),it->col()) = it->value(); + + // pass 3: + trMat.sumupDuplicates(); + + // pass 4: transposed copy -> implicit sorting + mat = trMat; +} + +} + + +/** Fill the matrix \c *this with the list of \em triplets defined by the iterator range \a begin - \b. + * + * A \em triplet is a tuple (i,j,value) defining a non-zero element. + * The input list of triplets does not have to be sorted, and can contains duplicated elements. + * In any case, the result is a \b sorted and \b compressed sparse matrix where the duplicates have been summed up. + * This is a \em O(n) operation, with \em n the number of triplet elements. + * The initial contents of \c *this is destroyed. + * The matrix \c *this must be properly resized beforehand using the SparseMatrix(Index,Index) constructor, + * or the resize(Index,Index) method. The sizes are not extracted from the triplet list. + * + * The \a InputIterators value_type must provide the following interface: + * \code + * Scalar value() const; // the value + * Scalar row() const; // the row index i + * Scalar col() const; // the column index j + * \endcode + * See for instance the Eigen::Triplet template class. + * + * Here is a typical usage example: + * \code + typedef Triplet T; + std::vector tripletList; + triplets.reserve(estimation_of_entries); + for(...) + { + // ... + tripletList.push_back(T(i,j,v_ij)); + } + SparseMatrixType m(rows,cols); + m.setFromTriplets(tripletList.begin(), tripletList.end()); + // m is ready to go! + * \endcode + * + * \warning The list of triplets is read multiple times (at least twice). Therefore, it is not recommended to define + * an abstract iterator over a complex data-structure that would be expensive to evaluate. The triplets should rather + * be explicitely stored into a std::vector for instance. + */ +template +template +void SparseMatrix::setFromTriplets(const InputIterators& begin, const InputIterators& end) +{ + internal::set_from_triplets(begin, end, *this); +} + +/** \internal */ +template +void SparseMatrix::sumupDuplicates() +{ + eigen_assert(!isCompressed()); + // TODO, in practice we should be able to use m_innerNonZeros for that task + VectorXi wi(innerSize()); + wi.fill(-1); + Index count = 0; + // for each inner-vector, wi[inner_index] will hold the position of first element into the index/value buffers + for(int j=0; j=start) + { + // we already meet this entry => accumulate it + m_data.value(wi(i)) += m_data.value(k); + } + else + { + m_data.value(count) = m_data.value(k); + m_data.index(count) = m_data.index(k); + wi(i) = count; + ++count; + } + } + m_outerIndex[j] = start; + } + m_outerIndex[m_outerSize] = count; + + // turn the matrix into compressed form + delete[] m_innerNonZeros; + m_innerNonZeros = 0; + m_data.resize(m_outerIndex[m_outerSize]); +} + +} // end namespace Eigen + +#endif // EIGEN_SPARSEMATRIX_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseMatrixBase.h b/extern/Eigen3/Eigen/src/SparseCore/SparseMatrixBase.h new file mode 100644 index 00000000000..9a1258097fe --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseMatrixBase.h @@ -0,0 +1,458 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2011 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSEMATRIXBASE_H +#define EIGEN_SPARSEMATRIXBASE_H + +namespace Eigen { + +/** \ingroup SparseCore_Module + * + * \class SparseMatrixBase + * + * \brief Base class of any sparse matrices or sparse expressions + * + * \tparam Derived + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEMATRIXBASE_PLUGIN. + */ +template class SparseMatrixBase : public EigenBase +{ + public: + + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + typedef typename internal::add_const_on_value_type_if_arithmetic< + typename internal::packet_traits::type + >::type PacketReturnType; + + typedef SparseMatrixBase StorageBaseType; + typedef EigenBase Base; + + template + Derived& operator=(const EigenBase &other) + { + other.derived().evalTo(derived()); + return derived(); + } + + enum { + + RowsAtCompileTime = internal::traits::RowsAtCompileTime, + /**< The number of rows at compile-time. This is just a copy of the value provided + * by the \a Derived type. If a value is not known at compile-time, + * it is set to the \a Dynamic constant. + * \sa MatrixBase::rows(), MatrixBase::cols(), ColsAtCompileTime, SizeAtCompileTime */ + + ColsAtCompileTime = internal::traits::ColsAtCompileTime, + /**< The number of columns at compile-time. This is just a copy of the value provided + * by the \a Derived type. If a value is not known at compile-time, + * it is set to the \a Dynamic constant. + * \sa MatrixBase::rows(), MatrixBase::cols(), RowsAtCompileTime, SizeAtCompileTime */ + + + SizeAtCompileTime = (internal::size_at_compile_time::RowsAtCompileTime, + internal::traits::ColsAtCompileTime>::ret), + /**< This is equal to the number of coefficients, i.e. the number of + * rows times the number of columns, or to \a Dynamic if this is not + * known at compile-time. \sa RowsAtCompileTime, ColsAtCompileTime */ + + MaxRowsAtCompileTime = RowsAtCompileTime, + MaxColsAtCompileTime = ColsAtCompileTime, + + MaxSizeAtCompileTime = (internal::size_at_compile_time::ret), + + IsVectorAtCompileTime = RowsAtCompileTime == 1 || ColsAtCompileTime == 1, + /**< This is set to true if either the number of rows or the number of + * columns is known at compile-time to be equal to 1. Indeed, in that case, + * we are dealing with a column-vector (if there is only one column) or with + * a row-vector (if there is only one row). */ + + Flags = internal::traits::Flags, + /**< This stores expression \ref flags flags which may or may not be inherited by new expressions + * constructed from this one. See the \ref flags "list of flags". + */ + + CoeffReadCost = internal::traits::CoeffReadCost, + /**< This is a rough measure of how expensive it is to read one coefficient from + * this expression. + */ + + IsRowMajor = Flags&RowMajorBit ? 1 : 0, + + #ifndef EIGEN_PARSED_BY_DOXYGEN + _HasDirectAccess = (int(Flags)&DirectAccessBit) ? 1 : 0 // workaround sunCC + #endif + }; + + /** \internal the return type of MatrixBase::adjoint() */ + typedef typename internal::conditional::IsComplex, + CwiseUnaryOp, Eigen::Transpose >, + Transpose + >::type AdjointReturnType; + + + typedef SparseMatrix PlainObject; + + +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** This is the "real scalar" type; if the \a Scalar type is already real numbers + * (e.g. int, float or double) then \a RealScalar is just the same as \a Scalar. If + * \a Scalar is \a std::complex then RealScalar is \a T. + * + * \sa class NumTraits + */ + typedef typename NumTraits::Real RealScalar; + + /** \internal the return type of coeff() + */ + typedef typename internal::conditional<_HasDirectAccess, const Scalar&, Scalar>::type CoeffReturnType; + + /** \internal Represents a matrix with all coefficients equal to one another*/ + typedef CwiseNullaryOp,Matrix > ConstantReturnType; + + /** type of the equivalent square matrix */ + typedef Matrix SquareMatrixType; + + inline const Derived& derived() const { return *static_cast(this); } + inline Derived& derived() { return *static_cast(this); } + inline Derived& const_cast_derived() const + { return *static_cast(const_cast(this)); } +#endif // not EIGEN_PARSED_BY_DOXYGEN + +#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::SparseMatrixBase +# include "../plugins/CommonCwiseUnaryOps.h" +# include "../plugins/CommonCwiseBinaryOps.h" +# include "../plugins/MatrixCwiseUnaryOps.h" +# include "../plugins/MatrixCwiseBinaryOps.h" +# ifdef EIGEN_SPARSEMATRIXBASE_PLUGIN +# include EIGEN_SPARSEMATRIXBASE_PLUGIN +# endif +# undef EIGEN_CURRENT_STORAGE_BASE_CLASS +#undef EIGEN_CURRENT_STORAGE_BASE_CLASS + + + /** \returns the number of rows. \sa cols() */ + inline Index rows() const { return derived().rows(); } + /** \returns the number of columns. \sa rows() */ + inline Index cols() const { return derived().cols(); } + /** \returns the number of coefficients, which is \a rows()*cols(). + * \sa rows(), cols(). */ + inline Index size() const { return rows() * cols(); } + /** \returns the number of nonzero coefficients which is in practice the number + * of stored coefficients. */ + inline Index nonZeros() const { return derived().nonZeros(); } + /** \returns true if either the number of rows or the number of columns is equal to 1. + * In other words, this function returns + * \code rows()==1 || cols()==1 \endcode + * \sa rows(), cols(), IsVectorAtCompileTime. */ + inline bool isVector() const { return rows()==1 || cols()==1; } + /** \returns the size of the storage major dimension, + * i.e., the number of columns for a columns major matrix, and the number of rows otherwise */ + Index outerSize() const { return (int(Flags)&RowMajorBit) ? this->rows() : this->cols(); } + /** \returns the size of the inner dimension according to the storage order, + * i.e., the number of rows for a columns major matrix, and the number of cols otherwise */ + Index innerSize() const { return (int(Flags)&RowMajorBit) ? this->cols() : this->rows(); } + + bool isRValue() const { return m_isRValue; } + Derived& markAsRValue() { m_isRValue = true; return derived(); } + + SparseMatrixBase() : m_isRValue(false) { /* TODO check flags */ } + + + template + Derived& operator=(const ReturnByValue& other) + { + other.evalTo(derived()); + return derived(); + } + + + template + inline Derived& operator=(const SparseMatrixBase& other) + { + return assign(other.derived()); + } + + inline Derived& operator=(const Derived& other) + { +// if (other.isRValue()) +// derived().swap(other.const_cast_derived()); +// else + return assign(other.derived()); + } + + protected: + + template + inline Derived& assign(const OtherDerived& other) + { + const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); + const Index outerSize = (int(OtherDerived::Flags) & RowMajorBit) ? other.rows() : other.cols(); + if ((!transpose) && other.isRValue()) + { + // eval without temporary + derived().resize(other.rows(), other.cols()); + derived().setZero(); + derived().reserve((std::max)(this->rows(),this->cols())*2); + for (Index j=0; j + inline void assignGeneric(const OtherDerived& other) + { + //const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); + eigen_assert(( ((internal::traits::SupportedAccessPatterns&OuterRandomAccessPattern)==OuterRandomAccessPattern) || + (!((Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit)))) && + "the transpose operation is supposed to be handled in SparseMatrix::operator="); + + enum { Flip = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit) }; + + const Index outerSize = other.outerSize(); + //typedef typename internal::conditional, Derived>::type TempType; + // thanks to shallow copies, we always eval to a tempary + Derived temp(other.rows(), other.cols()); + + temp.reserve((std::max)(this->rows(),this->cols())*2); + for (Index j=0; j + inline Derived& operator=(const SparseSparseProduct& product); + + friend std::ostream & operator << (std::ostream & s, const SparseMatrixBase& m) + { + typedef typename Derived::Nested Nested; + typedef typename internal::remove_all::type NestedCleaned; + + if (Flags&RowMajorBit) + { + const Nested nm(m.derived()); + for (Index row=0; row trans = m; + s << static_cast >&>(trans); + } + } + return s; + } + + template + Derived& operator+=(const SparseMatrixBase& other); + template + Derived& operator-=(const SparseMatrixBase& other); + + Derived& operator*=(const Scalar& other); + Derived& operator/=(const Scalar& other); + + #define EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE \ + CwiseBinaryOp< \ + internal::scalar_product_op< \ + typename internal::scalar_product_traits< \ + typename internal::traits::Scalar, \ + typename internal::traits::Scalar \ + >::ReturnType \ + >, \ + Derived, \ + OtherDerived \ + > + + template + EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE + cwiseProduct(const MatrixBase &other) const; + + // sparse * sparse + template + const typename SparseSparseProductReturnType::Type + operator*(const SparseMatrixBase &other) const; + + // sparse * diagonal + template + const SparseDiagonalProduct + operator*(const DiagonalBase &other) const; + + // diagonal * sparse + template friend + const SparseDiagonalProduct + operator*(const DiagonalBase &lhs, const SparseMatrixBase& rhs) + { return SparseDiagonalProduct(lhs.derived(), rhs.derived()); } + + /** dense * sparse (return a dense object unless it is an outer product) */ + template friend + const typename DenseSparseProductReturnType::Type + operator*(const MatrixBase& lhs, const Derived& rhs) + { return typename DenseSparseProductReturnType::Type(lhs.derived(),rhs); } + + /** sparse * dense (returns a dense object unless it is an outer product) */ + template + const typename SparseDenseProductReturnType::Type + operator*(const MatrixBase &other) const; + + /** \returns an expression of P H P^-1 where H is the matrix represented by \c *this */ + SparseSymmetricPermutationProduct twistedBy(const PermutationMatrix& perm) const + { + return SparseSymmetricPermutationProduct(derived(), perm); + } + + template + Derived& operator*=(const SparseMatrixBase& other); + + #ifdef EIGEN2_SUPPORT + // deprecated + template + typename internal::plain_matrix_type_column_major::type + solveTriangular(const MatrixBase& other) const; + + // deprecated + template + void solveTriangularInPlace(MatrixBase& other) const; + #endif // EIGEN2_SUPPORT + + template + inline const SparseTriangularView triangularView() const; + + template inline const SparseSelfAdjointView selfadjointView() const; + template inline SparseSelfAdjointView selfadjointView(); + + template Scalar dot(const MatrixBase& other) const; + template Scalar dot(const SparseMatrixBase& other) const; + RealScalar squaredNorm() const; + RealScalar norm() const; + + Transpose transpose() { return derived(); } + const Transpose transpose() const { return derived(); } + const AdjointReturnType adjoint() const { return transpose(); } + + // sub-vector + SparseInnerVectorSet row(Index i); + const SparseInnerVectorSet row(Index i) const; + SparseInnerVectorSet col(Index j); + const SparseInnerVectorSet col(Index j) const; + SparseInnerVectorSet innerVector(Index outer); + const SparseInnerVectorSet innerVector(Index outer) const; + + // set of sub-vectors + SparseInnerVectorSet subrows(Index start, Index size); + const SparseInnerVectorSet subrows(Index start, Index size) const; + SparseInnerVectorSet subcols(Index start, Index size); + const SparseInnerVectorSet subcols(Index start, Index size) const; + + SparseInnerVectorSet middleRows(Index start, Index size); + const SparseInnerVectorSet middleRows(Index start, Index size) const; + SparseInnerVectorSet middleCols(Index start, Index size); + const SparseInnerVectorSet middleCols(Index start, Index size) const; + SparseInnerVectorSet innerVectors(Index outerStart, Index outerSize); + const SparseInnerVectorSet innerVectors(Index outerStart, Index outerSize) const; + + /** \internal use operator= */ + template + void evalTo(MatrixBase& dst) const + { + dst.setZero(); + for (Index j=0; j toDense() const + { + return derived(); + } + + template + bool isApprox(const SparseMatrixBase& other, + RealScalar prec = NumTraits::dummy_precision()) const + { return toDense().isApprox(other.toDense(),prec); } + + template + bool isApprox(const MatrixBase& other, + RealScalar prec = NumTraits::dummy_precision()) const + { return toDense().isApprox(other,prec); } + + /** \returns the matrix or vector obtained by evaluating this expression. + * + * Notice that in the case of a plain matrix or vector (not an expression) this function just returns + * a const reference, in order to avoid a useless copy. + */ + inline const typename internal::eval::type eval() const + { return typename internal::eval::type(derived()); } + + Scalar sum() const; + + protected: + + bool m_isRValue; +}; + +} // end namespace Eigen + +#endif // EIGEN_SPARSEMATRIXBASE_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparsePermutation.h b/extern/Eigen3/Eigen/src/SparseCore/SparsePermutation.h new file mode 100644 index 00000000000..b897b7595b5 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparsePermutation.h @@ -0,0 +1,148 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2012 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSE_PERMUTATION_H +#define EIGEN_SPARSE_PERMUTATION_H + +// This file implements sparse * permutation products + +namespace Eigen { + +namespace internal { + +template +struct traits > +{ + typedef typename remove_all::type MatrixTypeNestedCleaned; + typedef typename MatrixTypeNestedCleaned::Scalar Scalar; + typedef typename MatrixTypeNestedCleaned::Index Index; + enum { + SrcStorageOrder = MatrixTypeNestedCleaned::Flags&RowMajorBit ? RowMajor : ColMajor, + MoveOuter = SrcStorageOrder==RowMajor ? Side==OnTheLeft : Side==OnTheRight + }; + + typedef typename internal::conditional, + SparseMatrix >::type ReturnType; +}; + +template +struct permut_sparsematrix_product_retval + : public ReturnByValue > +{ + typedef typename remove_all::type MatrixTypeNestedCleaned; + typedef typename MatrixTypeNestedCleaned::Scalar Scalar; + typedef typename MatrixTypeNestedCleaned::Index Index; + + enum { + SrcStorageOrder = MatrixTypeNestedCleaned::Flags&RowMajorBit ? RowMajor : ColMajor, + MoveOuter = SrcStorageOrder==RowMajor ? Side==OnTheLeft : Side==OnTheRight + }; + + permut_sparsematrix_product_retval(const PermutationType& perm, const MatrixType& matrix) + : m_permutation(perm), m_matrix(matrix) + {} + + inline int rows() const { return m_matrix.rows(); } + inline int cols() const { return m_matrix.cols(); } + + template inline void evalTo(Dest& dst) const + { + if(MoveOuter) + { + SparseMatrix tmp(m_matrix.rows(), m_matrix.cols()); + VectorXi sizes(m_matrix.outerSize()); + for(Index j=0; j tmp(m_matrix.rows(), m_matrix.cols()); + VectorXi sizes(tmp.outerSize()); + sizes.setZero(); + PermutationMatrix perm; + if((Side==OnTheLeft) ^ Transposed) + perm = m_permutation; + else + perm = m_permutation.transpose(); + + for(Index j=0; j +inline const internal::permut_sparsematrix_product_retval, SparseDerived, OnTheRight, false> +operator*(const SparseMatrixBase& matrix, const PermutationBase& perm) +{ + return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheRight, false>(perm, matrix.derived()); +} + +/** \returns the matrix with the permutation applied to the rows + */ +template +inline const internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, false> +operator*( const PermutationBase& perm, const SparseMatrixBase& matrix) +{ + return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, false>(perm, matrix.derived()); +} + + + +/** \returns the matrix with the inverse permutation applied to the columns. + */ +template +inline const internal::permut_sparsematrix_product_retval, SparseDerived, OnTheRight, true> +operator*(const SparseMatrixBase& matrix, const Transpose >& tperm) +{ + return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheRight, true>(tperm.nestedPermutation(), matrix.derived()); +} + +/** \returns the matrix with the inverse permutation applied to the rows. + */ +template +inline const internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, true> +operator*(const Transpose >& tperm, const SparseMatrixBase& matrix) +{ + return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, true>(tperm.nestedPermutation(), matrix.derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_SPARSE_SELFADJOINTVIEW_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseProduct.h b/extern/Eigen3/Eigen/src/SparseCore/SparseProduct.h new file mode 100644 index 00000000000..6a555b83434 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseProduct.h @@ -0,0 +1,186 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSEPRODUCT_H +#define EIGEN_SPARSEPRODUCT_H + +namespace Eigen { + +template +struct SparseSparseProductReturnType +{ + typedef typename internal::traits::Scalar Scalar; + enum { + LhsRowMajor = internal::traits::Flags & RowMajorBit, + RhsRowMajor = internal::traits::Flags & RowMajorBit, + TransposeRhs = (!LhsRowMajor) && RhsRowMajor, + TransposeLhs = LhsRowMajor && (!RhsRowMajor) + }; + + typedef typename internal::conditional, + typename internal::nested::type>::type LhsNested; + + typedef typename internal::conditional, + typename internal::nested::type>::type RhsNested; + + typedef SparseSparseProduct Type; +}; + +namespace internal { +template +struct traits > +{ + typedef MatrixXpr XprKind; + // clean the nested types: + typedef typename remove_all::type _LhsNested; + typedef typename remove_all::type _RhsNested; + typedef typename _LhsNested::Scalar Scalar; + typedef typename promote_index_type::Index, + typename traits<_RhsNested>::Index>::type Index; + + enum { + LhsCoeffReadCost = _LhsNested::CoeffReadCost, + RhsCoeffReadCost = _RhsNested::CoeffReadCost, + LhsFlags = _LhsNested::Flags, + RhsFlags = _RhsNested::Flags, + + RowsAtCompileTime = _LhsNested::RowsAtCompileTime, + ColsAtCompileTime = _RhsNested::ColsAtCompileTime, + MaxRowsAtCompileTime = _LhsNested::MaxRowsAtCompileTime, + MaxColsAtCompileTime = _RhsNested::MaxColsAtCompileTime, + + InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(_LhsNested::ColsAtCompileTime, _RhsNested::RowsAtCompileTime), + + EvalToRowMajor = (RhsFlags & LhsFlags & RowMajorBit), + + RemovedBits = ~(EvalToRowMajor ? 0 : RowMajorBit), + + Flags = (int(LhsFlags | RhsFlags) & HereditaryBits & RemovedBits) + | EvalBeforeAssigningBit + | EvalBeforeNestingBit, + + CoeffReadCost = Dynamic + }; + + typedef Sparse StorageKind; +}; + +} // end namespace internal + +template +class SparseSparseProduct : internal::no_assignment_operator, + public SparseMatrixBase > +{ + public: + + typedef SparseMatrixBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(SparseSparseProduct) + + private: + + typedef typename internal::traits::_LhsNested _LhsNested; + typedef typename internal::traits::_RhsNested _RhsNested; + + public: + + template + EIGEN_STRONG_INLINE SparseSparseProduct(const Lhs& lhs, const Rhs& rhs) + : m_lhs(lhs), m_rhs(rhs), m_tolerance(0), m_conservative(true) + { + init(); + } + + template + EIGEN_STRONG_INLINE SparseSparseProduct(const Lhs& lhs, const Rhs& rhs, RealScalar tolerance) + : m_lhs(lhs), m_rhs(rhs), m_tolerance(tolerance), m_conservative(false) + { + init(); + } + + SparseSparseProduct pruned(Scalar reference = 0, RealScalar epsilon = NumTraits::dummy_precision()) const + { + return SparseSparseProduct(m_lhs,m_rhs,internal::abs(reference)*epsilon); + } + + template + void evalTo(Dest& result) const + { + if(m_conservative) + internal::conservative_sparse_sparse_product_selector<_LhsNested, _RhsNested, Dest>::run(lhs(),rhs(),result); + else + internal::sparse_sparse_product_with_pruning_selector<_LhsNested, _RhsNested, Dest>::run(lhs(),rhs(),result,m_tolerance); + } + + EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); } + EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); } + + EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; } + EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; } + + protected: + void init() + { + eigen_assert(m_lhs.cols() == m_rhs.rows()); + + enum { + ProductIsValid = _LhsNested::ColsAtCompileTime==Dynamic + || _RhsNested::RowsAtCompileTime==Dynamic + || int(_LhsNested::ColsAtCompileTime)==int(_RhsNested::RowsAtCompileTime), + AreVectors = _LhsNested::IsVectorAtCompileTime && _RhsNested::IsVectorAtCompileTime, + SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(_LhsNested,_RhsNested) + }; + // note to the lost user: + // * for a dot product use: v1.dot(v2) + // * for a coeff-wise product use: v1.cwise()*v2 + EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), + INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) + EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), + INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) + EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) + } + + LhsNested m_lhs; + RhsNested m_rhs; + RealScalar m_tolerance; + bool m_conservative; +}; + +// sparse = sparse * sparse +template +template +inline Derived& SparseMatrixBase::operator=(const SparseSparseProduct& product) +{ + product.evalTo(derived()); + return derived(); +} + +/** \returns an expression of the product of two sparse matrices. + * By default a conservative product preserving the symbolic non zeros is performed. + * The automatic pruning of the small values can be achieved by calling the pruned() function + * in which case a totally different product algorithm is employed: + * \code + * C = (A*B).pruned(); // supress numerical zeros (exact) + * C = (A*B).pruned(ref); + * C = (A*B).pruned(ref,epsilon); + * \endcode + * where \c ref is a meaningful non zero reference value. + * */ +template +template +inline const typename SparseSparseProductReturnType::Type +SparseMatrixBase::operator*(const SparseMatrixBase &other) const +{ + return typename SparseSparseProductReturnType::Type(derived(), other.derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_SPARSEPRODUCT_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseRedux.h b/extern/Eigen3/Eigen/src/SparseCore/SparseRedux.h new file mode 100644 index 00000000000..f3da93a71d4 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseRedux.h @@ -0,0 +1,45 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSEREDUX_H +#define EIGEN_SPARSEREDUX_H + +namespace Eigen { + +template +typename internal::traits::Scalar +SparseMatrixBase::sum() const +{ + eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); + Scalar res(0); + for (Index j=0; j +typename internal::traits >::Scalar +SparseMatrix<_Scalar,_Options,_Index>::sum() const +{ + eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); + return Matrix::Map(&m_data.value(0), m_data.size()).sum(); +} + +template +typename internal::traits >::Scalar +SparseVector<_Scalar,_Options,_Index>::sum() const +{ + eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); + return Matrix::Map(&m_data.value(0), m_data.size()).sum(); +} + +} // end namespace Eigen + +#endif // EIGEN_SPARSEREDUX_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseSelfAdjointView.h b/extern/Eigen3/Eigen/src/SparseCore/SparseSelfAdjointView.h new file mode 100644 index 00000000000..86ec0a6c5e2 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseSelfAdjointView.h @@ -0,0 +1,480 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSE_SELFADJOINTVIEW_H +#define EIGEN_SPARSE_SELFADJOINTVIEW_H + +namespace Eigen { + +/** \ingroup SparseCore_Module + * \class SparseSelfAdjointView + * + * \brief Pseudo expression to manipulate a triangular sparse matrix as a selfadjoint matrix. + * + * \param MatrixType the type of the dense matrix storing the coefficients + * \param UpLo can be either \c #Lower or \c #Upper + * + * This class is an expression of a sefladjoint matrix from a triangular part of a matrix + * with given dense storage of the coefficients. It is the return type of MatrixBase::selfadjointView() + * and most of the time this is the only way that it is used. + * + * \sa SparseMatrixBase::selfadjointView() + */ +template +class SparseSelfAdjointTimeDenseProduct; + +template +class DenseTimeSparseSelfAdjointProduct; + +namespace internal { + +template +struct traits > : traits { +}; + +template +void permute_symm_to_symm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm = 0); + +template +void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm = 0); + +} + +template class SparseSelfAdjointView + : public EigenBase > +{ + public: + + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::Index Index; + typedef Matrix VectorI; + typedef typename MatrixType::Nested MatrixTypeNested; + typedef typename internal::remove_all::type _MatrixTypeNested; + + inline SparseSelfAdjointView(const MatrixType& matrix) : m_matrix(matrix) + { + eigen_assert(rows()==cols() && "SelfAdjointView is only for squared matrices"); + } + + inline Index rows() const { return m_matrix.rows(); } + inline Index cols() const { return m_matrix.cols(); } + + /** \internal \returns a reference to the nested matrix */ + const _MatrixTypeNested& matrix() const { return m_matrix; } + _MatrixTypeNested& matrix() { return m_matrix.const_cast_derived(); } + + /** Efficient sparse self-adjoint matrix times dense vector/matrix product */ + template + SparseSelfAdjointTimeDenseProduct + operator*(const MatrixBase& rhs) const + { + return SparseSelfAdjointTimeDenseProduct(m_matrix, rhs.derived()); + } + + /** Efficient dense vector/matrix times sparse self-adjoint matrix product */ + template friend + DenseTimeSparseSelfAdjointProduct + operator*(const MatrixBase& lhs, const SparseSelfAdjointView& rhs) + { + return DenseTimeSparseSelfAdjointProduct(lhs.derived(), rhs.m_matrix); + } + + /** Perform a symmetric rank K update of the selfadjoint matrix \c *this: + * \f$ this = this + \alpha ( u u^* ) \f$ where \a u is a vector or matrix. + * + * \returns a reference to \c *this + * + * To perform \f$ this = this + \alpha ( u^* u ) \f$ you can simply + * call this function with u.adjoint(). + */ + template + SparseSelfAdjointView& rankUpdate(const SparseMatrixBase& u, Scalar alpha = Scalar(1)); + + /** \internal triggered by sparse_matrix = SparseSelfadjointView; */ + template void evalTo(SparseMatrix& _dest) const + { + internal::permute_symm_to_fullsymm(m_matrix, _dest); + } + + template void evalTo(DynamicSparseMatrix& _dest) const + { + // TODO directly evaluate into _dest; + SparseMatrix tmp(_dest.rows(),_dest.cols()); + internal::permute_symm_to_fullsymm(m_matrix, tmp); + _dest = tmp; + } + + /** \returns an expression of P H P^-1 */ + SparseSymmetricPermutationProduct<_MatrixTypeNested,UpLo> twistedBy(const PermutationMatrix& perm) const + { + return SparseSymmetricPermutationProduct<_MatrixTypeNested,UpLo>(m_matrix, perm); + } + + template + SparseSelfAdjointView& operator=(const SparseSymmetricPermutationProduct& permutedMatrix) + { + permutedMatrix.evalTo(*this); + return *this; + } + + + SparseSelfAdjointView& operator=(const SparseSelfAdjointView& src) + { + PermutationMatrix pnull; + return *this = src.twistedBy(pnull); + } + + template + SparseSelfAdjointView& operator=(const SparseSelfAdjointView& src) + { + PermutationMatrix pnull; + return *this = src.twistedBy(pnull); + } + + + // const SparseLLT llt() const; + // const SparseLDLT ldlt() const; + + protected: + + typename MatrixType::Nested m_matrix; + mutable VectorI m_countPerRow; + mutable VectorI m_countPerCol; +}; + +/*************************************************************************** +* Implementation of SparseMatrixBase methods +***************************************************************************/ + +template +template +const SparseSelfAdjointView SparseMatrixBase::selfadjointView() const +{ + return derived(); +} + +template +template +SparseSelfAdjointView SparseMatrixBase::selfadjointView() +{ + return derived(); +} + +/*************************************************************************** +* Implementation of SparseSelfAdjointView methods +***************************************************************************/ + +template +template +SparseSelfAdjointView& +SparseSelfAdjointView::rankUpdate(const SparseMatrixBase& u, Scalar alpha) +{ + SparseMatrix tmp = u * u.adjoint(); + if(alpha==Scalar(0)) + m_matrix.const_cast_derived() = tmp.template triangularView(); + else + m_matrix.const_cast_derived() += alpha * tmp.template triangularView(); + + return *this; +} + +/*************************************************************************** +* Implementation of sparse self-adjoint time dense matrix +***************************************************************************/ + +namespace internal { +template +struct traits > + : traits, Lhs, Rhs> > +{ + typedef Dense StorageKind; +}; +} + +template +class SparseSelfAdjointTimeDenseProduct + : public ProductBase, Lhs, Rhs> +{ + public: + EIGEN_PRODUCT_PUBLIC_INTERFACE(SparseSelfAdjointTimeDenseProduct) + + SparseSelfAdjointTimeDenseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) + {} + + template void scaleAndAddTo(Dest& dest, Scalar alpha) const + { + // TODO use alpha + eigen_assert(alpha==Scalar(1) && "alpha != 1 is not implemented yet, sorry"); + typedef typename internal::remove_all::type _Lhs; + typedef typename internal::remove_all::type _Rhs; + typedef typename _Lhs::InnerIterator LhsInnerIterator; + enum { + LhsIsRowMajor = (_Lhs::Flags&RowMajorBit)==RowMajorBit, + ProcessFirstHalf = + ((UpLo&(Upper|Lower))==(Upper|Lower)) + || ( (UpLo&Upper) && !LhsIsRowMajor) + || ( (UpLo&Lower) && LhsIsRowMajor), + ProcessSecondHalf = !ProcessFirstHalf + }; + for (Index j=0; j +struct traits > + : traits, Lhs, Rhs> > +{}; +} + +template +class DenseTimeSparseSelfAdjointProduct + : public ProductBase, Lhs, Rhs> +{ + public: + EIGEN_PRODUCT_PUBLIC_INTERFACE(DenseTimeSparseSelfAdjointProduct) + + DenseTimeSparseSelfAdjointProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) + {} + + template void scaleAndAddTo(Dest& /*dest*/, Scalar /*alpha*/) const + { + // TODO + } + + private: + DenseTimeSparseSelfAdjointProduct& operator=(const DenseTimeSparseSelfAdjointProduct&); +}; + +/*************************************************************************** +* Implementation of symmetric copies and permutations +***************************************************************************/ +namespace internal { + +template +struct traits > : traits { +}; + +template +void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm) +{ + typedef typename MatrixType::Index Index; + typedef typename MatrixType::Scalar Scalar; + typedef SparseMatrix Dest; + typedef Matrix VectorI; + + Dest& dest(_dest.derived()); + enum { + StorageOrderMatch = int(Dest::IsRowMajor) == int(MatrixType::IsRowMajor) + }; + + Index size = mat.rows(); + VectorI count; + count.resize(size); + count.setZero(); + dest.resize(size,size); + for(Index j = 0; jc) || ( UpLo==Upper && rc) || ( (UpLo&Upper)==Upper && r +void permute_symm_to_symm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm) +{ + typedef typename MatrixType::Index Index; + typedef typename MatrixType::Scalar Scalar; + SparseMatrix& dest(_dest.derived()); + typedef Matrix VectorI; + enum { + SrcOrder = MatrixType::IsRowMajor ? RowMajor : ColMajor, + StorageOrderMatch = int(SrcOrder) == int(DstOrder), + DstUpLo = DstOrder==RowMajor ? (_DstUpLo==Upper ? Lower : Upper) : _DstUpLo, + SrcUpLo = SrcOrder==RowMajor ? (_SrcUpLo==Upper ? Lower : Upper) : _SrcUpLo + }; + + Index size = mat.rows(); + VectorI count(size); + count.setZero(); + dest.resize(size,size); + for(Index j = 0; jj)) + continue; + + Index ip = perm ? perm[i] : i; + count[int(DstUpLo)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++; + } + } + dest.outerIndexPtr()[0] = 0; + for(Index j=0; jj)) + continue; + + Index jp = perm ? perm[j] : j; + Index ip = perm? perm[i] : i; + + Index k = count[int(DstUpLo)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++; + dest.innerIndexPtr()[k] = int(DstUpLo)==int(Lower) ? (std::max)(ip,jp) : (std::min)(ip,jp); + + if(!StorageOrderMatch) std::swap(ip,jp); + if( ((int(DstUpLo)==int(Lower) && ipjp))) + dest.valuePtr()[k] = conj(it.value()); + else + dest.valuePtr()[k] = it.value(); + } + } +} + +} + +template +class SparseSymmetricPermutationProduct + : public EigenBase > +{ + public: + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::Index Index; + protected: + typedef PermutationMatrix Perm; + public: + typedef Matrix VectorI; + typedef typename MatrixType::Nested MatrixTypeNested; + typedef typename internal::remove_all::type _MatrixTypeNested; + + SparseSymmetricPermutationProduct(const MatrixType& mat, const Perm& perm) + : m_matrix(mat), m_perm(perm) + {} + + inline Index rows() const { return m_matrix.rows(); } + inline Index cols() const { return m_matrix.cols(); } + + template + void evalTo(SparseMatrix& _dest) const + { + internal::permute_symm_to_fullsymm(m_matrix,_dest,m_perm.indices().data()); + } + + template void evalTo(SparseSelfAdjointView& dest) const + { + internal::permute_symm_to_symm(m_matrix,dest.matrix(),m_perm.indices().data()); + } + + protected: + MatrixTypeNested m_matrix; + const Perm& m_perm; + +}; + +} // end namespace Eigen + +#endif // EIGEN_SPARSE_SELFADJOINTVIEW_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseSparseProductWithPruning.h b/extern/Eigen3/Eigen/src/SparseCore/SparseSparseProductWithPruning.h new file mode 100644 index 00000000000..2438ac573d0 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseSparseProductWithPruning.h @@ -0,0 +1,149 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2011 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSESPARSEPRODUCTWITHPRUNING_H +#define EIGEN_SPARSESPARSEPRODUCTWITHPRUNING_H + +namespace Eigen { + +namespace internal { + + +// perform a pseudo in-place sparse * sparse product assuming all matrices are col major +template +static void sparse_sparse_product_with_pruning_impl(const Lhs& lhs, const Rhs& rhs, ResultType& res, typename ResultType::RealScalar tolerance) +{ + // return sparse_sparse_product_with_pruning_impl2(lhs,rhs,res); + + typedef typename remove_all::type::Scalar Scalar; + typedef typename remove_all::type::Index Index; + + // make sure to call innerSize/outerSize since we fake the storage order. + Index rows = lhs.innerSize(); + Index cols = rhs.outerSize(); + //int size = lhs.outerSize(); + eigen_assert(lhs.outerSize() == rhs.innerSize()); + + // allocate a temporary buffer + AmbiVector tempVector(rows); + + // estimate the number of non zero entries + // given a rhs column containing Y non zeros, we assume that the respective Y columns + // of the lhs differs in average of one non zeros, thus the number of non zeros for + // the product of a rhs column with the lhs is X+Y where X is the average number of non zero + // per column of the lhs. + // Therefore, we have nnz(lhs*rhs) = nnz(lhs) + nnz(rhs) + Index estimated_nnz_prod = lhs.nonZeros() + rhs.nonZeros(); + + // mimics a resizeByInnerOuter: + if(ResultType::IsRowMajor) + res.resize(cols, rows); + else + res.resize(rows, cols); + + res.reserve(estimated_nnz_prod); + double ratioColRes = double(estimated_nnz_prod)/double(lhs.rows()*rhs.cols()); + for (Index j=0; j::Iterator it(tempVector,tolerance); it; ++it) + res.insertBackByOuterInner(j,it.index()) = it.value(); + } + res.finalize(); +} + +template::Flags&RowMajorBit, + int RhsStorageOrder = traits::Flags&RowMajorBit, + int ResStorageOrder = traits::Flags&RowMajorBit> +struct sparse_sparse_product_with_pruning_selector; + +template +struct sparse_sparse_product_with_pruning_selector +{ + typedef typename traits::type>::Scalar Scalar; + typedef typename ResultType::RealScalar RealScalar; + + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, RealScalar tolerance) + { + typename remove_all::type _res(res.rows(), res.cols()); + internal::sparse_sparse_product_with_pruning_impl(lhs, rhs, _res, tolerance); + res.swap(_res); + } +}; + +template +struct sparse_sparse_product_with_pruning_selector +{ + typedef typename ResultType::RealScalar RealScalar; + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, RealScalar tolerance) + { + // we need a col-major matrix to hold the result + typedef SparseMatrix SparseTemporaryType; + SparseTemporaryType _res(res.rows(), res.cols()); + internal::sparse_sparse_product_with_pruning_impl(lhs, rhs, _res, tolerance); + res = _res; + } +}; + +template +struct sparse_sparse_product_with_pruning_selector +{ + typedef typename ResultType::RealScalar RealScalar; + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, RealScalar tolerance) + { + // let's transpose the product to get a column x column product + typename remove_all::type _res(res.rows(), res.cols()); + internal::sparse_sparse_product_with_pruning_impl(rhs, lhs, _res, tolerance); + res.swap(_res); + } +}; + +template +struct sparse_sparse_product_with_pruning_selector +{ + typedef typename ResultType::RealScalar RealScalar; + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, RealScalar tolerance) + { + typedef SparseMatrix ColMajorMatrix; + ColMajorMatrix colLhs(lhs); + ColMajorMatrix colRhs(rhs); + internal::sparse_sparse_product_with_pruning_impl(colLhs, colRhs, res, tolerance); + + // let's transpose the product to get a column x column product +// typedef SparseMatrix SparseTemporaryType; +// SparseTemporaryType _res(res.cols(), res.rows()); +// sparse_sparse_product_with_pruning_impl(rhs, lhs, _res); +// res = _res.transpose(); + } +}; + +// NOTE the 2 others cases (col row *) must never occur since they are caught +// by ProductReturnType which transforms it to (col col *) by evaluating rhs. + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_SPARSESPARSEPRODUCTWITHPRUNING_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseTranspose.h b/extern/Eigen3/Eigen/src/SparseCore/SparseTranspose.h new file mode 100644 index 00000000000..273f9de688f --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseTranspose.h @@ -0,0 +1,61 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSETRANSPOSE_H +#define EIGEN_SPARSETRANSPOSE_H + +namespace Eigen { + +template class TransposeImpl + : public SparseMatrixBase > +{ + typedef typename internal::remove_all::type _MatrixTypeNested; + public: + + EIGEN_SPARSE_PUBLIC_INTERFACE(Transpose) + + class InnerIterator; + class ReverseInnerIterator; + + inline Index nonZeros() const { return derived().nestedExpression().nonZeros(); } +}; + +// NOTE: VC10 trigger an ICE if don't put typename TransposeImpl:: in front of Index, +// a typedef typename TransposeImpl::Index Index; +// does not fix the issue. +// An alternative is to define the nested class in the parent class itself. +template class TransposeImpl::InnerIterator + : public _MatrixTypeNested::InnerIterator +{ + typedef typename _MatrixTypeNested::InnerIterator Base; + public: + + EIGEN_STRONG_INLINE InnerIterator(const TransposeImpl& trans, typename TransposeImpl::Index outer) + : Base(trans.derived().nestedExpression(), outer) + {} + inline typename TransposeImpl::Index row() const { return Base::col(); } + inline typename TransposeImpl::Index col() const { return Base::row(); } +}; + +template class TransposeImpl::ReverseInnerIterator + : public _MatrixTypeNested::ReverseInnerIterator +{ + typedef typename _MatrixTypeNested::ReverseInnerIterator Base; + public: + + EIGEN_STRONG_INLINE ReverseInnerIterator(const TransposeImpl& xpr, typename TransposeImpl::Index outer) + : Base(xpr.derived().nestedExpression(), outer) + {} + inline typename TransposeImpl::Index row() const { return Base::col(); } + inline typename TransposeImpl::Index col() const { return Base::row(); } +}; + +} // end namespace Eigen + +#endif // EIGEN_SPARSETRANSPOSE_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseTriangularView.h b/extern/Eigen3/Eigen/src/SparseCore/SparseTriangularView.h new file mode 100644 index 00000000000..477e4bd94b0 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseTriangularView.h @@ -0,0 +1,164 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSE_TRIANGULARVIEW_H +#define EIGEN_SPARSE_TRIANGULARVIEW_H + +namespace Eigen { + +namespace internal { + +template +struct traits > +: public traits +{}; + +} // namespace internal + +template class SparseTriangularView + : public SparseMatrixBase > +{ + enum { SkipFirst = ((Mode&Lower) && !(MatrixType::Flags&RowMajorBit)) + || ((Mode&Upper) && (MatrixType::Flags&RowMajorBit)), + SkipLast = !SkipFirst, + HasUnitDiag = (Mode&UnitDiag) ? 1 : 0 + }; + + public: + + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseTriangularView) + + class InnerIterator; + class ReverseInnerIterator; + + inline Index rows() const { return m_matrix.rows(); } + inline Index cols() const { return m_matrix.cols(); } + + typedef typename MatrixType::Nested MatrixTypeNested; + typedef typename internal::remove_reference::type MatrixTypeNestedNonRef; + typedef typename internal::remove_all::type MatrixTypeNestedCleaned; + + inline SparseTriangularView(const MatrixType& matrix) : m_matrix(matrix) {} + + /** \internal */ + inline const MatrixTypeNestedCleaned& nestedExpression() const { return m_matrix; } + + template + typename internal::plain_matrix_type_column_major::type + solve(const MatrixBase& other) const; + + template void solveInPlace(MatrixBase& other) const; + template void solveInPlace(SparseMatrixBase& other) const; + + protected: + MatrixTypeNested m_matrix; +}; + +template +class SparseTriangularView::InnerIterator : public MatrixTypeNestedCleaned::InnerIterator +{ + typedef typename MatrixTypeNestedCleaned::InnerIterator Base; + public: + + EIGEN_STRONG_INLINE InnerIterator(const SparseTriangularView& view, Index outer) + : Base(view.nestedExpression(), outer), m_returnOne(false) + { + if(SkipFirst) + { + while((*this) && (HasUnitDiag ? this->index()<=outer : this->index()=Base::outer())) + { + if((!SkipFirst) && Base::operator bool()) + Base::operator++(); + m_returnOne = true; + } + } + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { + if(HasUnitDiag && m_returnOne) + m_returnOne = false; + else + { + Base::operator++(); + if(HasUnitDiag && (!SkipFirst) && ((!Base::operator bool()) || Base::index()>=Base::outer())) + { + if((!SkipFirst) && Base::operator bool()) + Base::operator++(); + m_returnOne = true; + } + } + return *this; + } + + inline Index row() const { return Base::row(); } + inline Index col() const { return Base::col(); } + inline Index index() const + { + if(HasUnitDiag && m_returnOne) return Base::outer(); + else return Base::index(); + } + inline Scalar value() const + { + if(HasUnitDiag && m_returnOne) return Scalar(1); + else return Base::value(); + } + + EIGEN_STRONG_INLINE operator bool() const + { + if(HasUnitDiag && m_returnOne) + return true; + return (SkipFirst ? Base::operator bool() : (Base::operator bool() && this->index() <= this->outer())); + } + protected: + bool m_returnOne; +}; + +template +class SparseTriangularView::ReverseInnerIterator : public MatrixTypeNestedCleaned::ReverseInnerIterator +{ + typedef typename MatrixTypeNestedCleaned::ReverseInnerIterator Base; + public: + + EIGEN_STRONG_INLINE ReverseInnerIterator(const SparseTriangularView& view, Index outer) + : Base(view.nestedExpression(), outer) + { + eigen_assert((!HasUnitDiag) && "ReverseInnerIterator does not support yet triangular views with a unit diagonal"); + if(SkipLast) + while((*this) && this->index()>outer) + --(*this); + } + + EIGEN_STRONG_INLINE InnerIterator& operator--() + { Base::operator--(); return *this; } + + inline Index row() const { return Base::row(); } + inline Index col() const { return Base::col(); } + + EIGEN_STRONG_INLINE operator bool() const + { + return SkipLast ? Base::operator bool() : (Base::operator bool() && this->index() >= this->outer()); + } +}; + +template +template +inline const SparseTriangularView +SparseMatrixBase::triangularView() const +{ + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_SPARSE_TRIANGULARVIEW_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseUtil.h b/extern/Eigen3/Eigen/src/SparseCore/SparseUtil.h new file mode 100644 index 00000000000..6062a086ff7 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseUtil.h @@ -0,0 +1,173 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSEUTIL_H +#define EIGEN_SPARSEUTIL_H + +namespace Eigen { + +#ifdef NDEBUG +#define EIGEN_DBG_SPARSE(X) +#else +#define EIGEN_DBG_SPARSE(X) X +#endif + +#define EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, Op) \ +template \ +EIGEN_STRONG_INLINE Derived& operator Op(const Eigen::SparseMatrixBase& other) \ +{ \ + return Base::operator Op(other.derived()); \ +} \ +EIGEN_STRONG_INLINE Derived& operator Op(const Derived& other) \ +{ \ + return Base::operator Op(other); \ +} + +#define EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, Op) \ +template \ +EIGEN_STRONG_INLINE Derived& operator Op(const Other& scalar) \ +{ \ + return Base::operator Op(scalar); \ +} + +#define EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATORS(Derived) \ +EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, =) \ +EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, +=) \ +EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, -=) \ +EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, *=) \ +EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, /=) + +#define _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, BaseClass) \ + typedef BaseClass Base; \ + typedef typename Eigen::internal::traits::Scalar Scalar; \ + typedef typename Eigen::NumTraits::Real RealScalar; \ + typedef typename Eigen::internal::nested::type Nested; \ + typedef typename Eigen::internal::traits::StorageKind StorageKind; \ + typedef typename Eigen::internal::traits::Index Index; \ + enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ + ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ + Flags = Eigen::internal::traits::Flags, \ + CoeffReadCost = Eigen::internal::traits::CoeffReadCost, \ + SizeAtCompileTime = Base::SizeAtCompileTime, \ + IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; \ + using Base::derived; \ + using Base::const_cast_derived; + +#define EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) \ + _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, Eigen::SparseMatrixBase) + +const int CoherentAccessPattern = 0x1; +const int InnerRandomAccessPattern = 0x2 | CoherentAccessPattern; +const int OuterRandomAccessPattern = 0x4 | CoherentAccessPattern; +const int RandomAccessPattern = 0x8 | OuterRandomAccessPattern | InnerRandomAccessPattern; + +template class SparseMatrixBase; +template class SparseMatrix; +template class DynamicSparseMatrix; +template class SparseVector; +template class MappedSparseMatrix; + +template class SparseInnerVectorSet; +template class SparseTriangularView; +template class SparseSelfAdjointView; +template class SparseDiagonalProduct; +template class SparseView; + +template class SparseSparseProduct; +template class SparseTimeDenseProduct; +template class DenseTimeSparseProduct; +template class SparseDenseOuterProduct; + +template struct SparseSparseProductReturnType; +template::ColsAtCompileTime> struct DenseSparseProductReturnType; +template::ColsAtCompileTime> struct SparseDenseProductReturnType; +template class SparseSymmetricPermutationProduct; + +namespace internal { + +template struct sparse_eval; + +template struct eval + : public sparse_eval::RowsAtCompileTime,traits::ColsAtCompileTime> +{}; + +template struct sparse_eval { + typedef typename traits::Scalar _Scalar; + enum { _Flags = traits::Flags| RowMajorBit }; + public: + typedef SparseVector<_Scalar, _Flags> type; +}; + +template struct sparse_eval { + typedef typename traits::Scalar _Scalar; + enum { _Flags = traits::Flags & (~RowMajorBit) }; + public: + typedef SparseVector<_Scalar, _Flags> type; +}; + +template struct sparse_eval { + typedef typename traits::Scalar _Scalar; + enum { _Flags = traits::Flags }; + public: + typedef SparseMatrix<_Scalar, _Flags> type; +}; + +template struct sparse_eval { + typedef typename traits::Scalar _Scalar; + public: + typedef Matrix<_Scalar, 1, 1> type; +}; + +template struct plain_matrix_type +{ + typedef typename traits::Scalar _Scalar; + enum { + _Flags = traits::Flags + }; + + public: + typedef SparseMatrix<_Scalar, _Flags> type; +}; + +} // end namespace internal + +/** \ingroup SparseCore_Module + * + * \class Triplet + * + * \brief A small structure to hold a non zero as a triplet (i,j,value). + * + * \sa SparseMatrix::setFromTriplets() + */ +template +class Triplet +{ +public: + Triplet() : m_row(0), m_col(0), m_value(0) {} + + Triplet(const Index& i, const Index& j, const Scalar& v = Scalar(0)) + : m_row(i), m_col(j), m_value(v) + {} + + /** \returns the row index of the element */ + const Index& row() const { return m_row; } + + /** \returns the column index of the element */ + const Index& col() const { return m_col; } + + /** \returns the value of the element */ + const Scalar& value() const { return m_value; } +protected: + Index m_row, m_col; + Scalar m_value; +}; + +} // end namespace Eigen + +#endif // EIGEN_SPARSEUTIL_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseVector.h b/extern/Eigen3/Eigen/src/SparseCore/SparseVector.h new file mode 100644 index 00000000000..c952f654038 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseVector.h @@ -0,0 +1,398 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSEVECTOR_H +#define EIGEN_SPARSEVECTOR_H + +namespace Eigen { + +/** \ingroup SparseCore_Module + * \class SparseVector + * + * \brief a sparse vector class + * + * \tparam _Scalar the scalar type, i.e. the type of the coefficients + * + * See http://www.netlib.org/linalg/html_templates/node91.html for details on the storage scheme. + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEVECTOR_PLUGIN. + */ + +namespace internal { +template +struct traits > +{ + typedef _Scalar Scalar; + typedef _Index Index; + typedef Sparse StorageKind; + typedef MatrixXpr XprKind; + enum { + IsColVector = (_Options & RowMajorBit) ? 0 : 1, + + RowsAtCompileTime = IsColVector ? Dynamic : 1, + ColsAtCompileTime = IsColVector ? 1 : Dynamic, + MaxRowsAtCompileTime = RowsAtCompileTime, + MaxColsAtCompileTime = ColsAtCompileTime, + Flags = _Options | NestByRefBit | LvalueBit | (IsColVector ? 0 : RowMajorBit), + CoeffReadCost = NumTraits::ReadCost, + SupportedAccessPatterns = InnerRandomAccessPattern + }; +}; +} + +template +class SparseVector + : public SparseMatrixBase > +{ + public: + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseVector) + EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, +=) + EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, -=) + + protected: + public: + + typedef SparseMatrixBase SparseBase; + enum { IsColVector = internal::traits::IsColVector }; + + enum { + Options = _Options + }; + + internal::CompressedStorage m_data; + Index m_size; + + internal::CompressedStorage& _data() { return m_data; } + internal::CompressedStorage& _data() const { return m_data; } + + public: + + EIGEN_STRONG_INLINE Index rows() const { return IsColVector ? m_size : 1; } + EIGEN_STRONG_INLINE Index cols() const { return IsColVector ? 1 : m_size; } + EIGEN_STRONG_INLINE Index innerSize() const { return m_size; } + EIGEN_STRONG_INLINE Index outerSize() const { return 1; } + + EIGEN_STRONG_INLINE const Scalar* valuePtr() const { return &m_data.value(0); } + EIGEN_STRONG_INLINE Scalar* valuePtr() { return &m_data.value(0); } + + EIGEN_STRONG_INLINE const Index* innerIndexPtr() const { return &m_data.index(0); } + EIGEN_STRONG_INLINE Index* innerIndexPtr() { return &m_data.index(0); } + + inline Scalar coeff(Index row, Index col) const + { + eigen_assert((IsColVector ? col : row)==0); + return coeff(IsColVector ? row : col); + } + inline Scalar coeff(Index i) const { return m_data.at(i); } + + inline Scalar& coeffRef(Index row, Index col) + { + eigen_assert((IsColVector ? col : row)==0); + return coeff(IsColVector ? row : col); + } + + /** \returns a reference to the coefficient value at given index \a i + * This operation involes a log(rho*size) binary search. If the coefficient does not + * exist yet, then a sorted insertion into a sequential buffer is performed. + * + * This insertion might be very costly if the number of nonzeros above \a i is large. + */ + inline Scalar& coeffRef(Index i) + { + return m_data.atWithInsertion(i); + } + + public: + + class InnerIterator; + class ReverseInnerIterator; + + inline void setZero() { m_data.clear(); } + + /** \returns the number of non zero coefficients */ + inline Index nonZeros() const { return static_cast(m_data.size()); } + + inline void startVec(Index outer) + { + EIGEN_UNUSED_VARIABLE(outer); + eigen_assert(outer==0); + } + + inline Scalar& insertBackByOuterInner(Index outer, Index inner) + { + EIGEN_UNUSED_VARIABLE(outer); + eigen_assert(outer==0); + return insertBack(inner); + } + inline Scalar& insertBack(Index i) + { + m_data.append(0, i); + return m_data.value(m_data.size()-1); + } + + inline Scalar& insert(Index row, Index col) + { + Index inner = IsColVector ? row : col; + Index outer = IsColVector ? col : row; + eigen_assert(outer==0); + return insert(inner); + } + Scalar& insert(Index i) + { + Index startId = 0; + Index p = Index(m_data.size()) - 1; + // TODO smart realloc + m_data.resize(p+2,1); + + while ( (p >= startId) && (m_data.index(p) > i) ) + { + m_data.index(p+1) = m_data.index(p); + m_data.value(p+1) = m_data.value(p); + --p; + } + m_data.index(p+1) = i; + m_data.value(p+1) = 0; + return m_data.value(p+1); + } + + /** + */ + inline void reserve(Index reserveSize) { m_data.reserve(reserveSize); } + + + inline void finalize() {} + + void prune(Scalar reference, RealScalar epsilon = NumTraits::dummy_precision()) + { + m_data.prune(reference,epsilon); + } + + void resize(Index rows, Index cols) + { + eigen_assert(rows==1 || cols==1); + resize(IsColVector ? rows : cols); + } + + void resize(Index newSize) + { + m_size = newSize; + m_data.clear(); + } + + void resizeNonZeros(Index size) { m_data.resize(size); } + + inline SparseVector() : m_size(0) { resize(0); } + + inline SparseVector(Index size) : m_size(0) { resize(size); } + + inline SparseVector(Index rows, Index cols) : m_size(0) { resize(rows,cols); } + + template + inline SparseVector(const SparseMatrixBase& other) + : m_size(0) + { + *this = other.derived(); + } + + inline SparseVector(const SparseVector& other) + : m_size(0) + { + *this = other.derived(); + } + + inline void swap(SparseVector& other) + { + std::swap(m_size, other.m_size); + m_data.swap(other.m_data); + } + + inline SparseVector& operator=(const SparseVector& other) + { + if (other.isRValue()) + { + swap(other.const_cast_derived()); + } + else + { + resize(other.size()); + m_data = other.m_data; + } + return *this; + } + + template + inline SparseVector& operator=(const SparseMatrixBase& other) + { + if (int(RowsAtCompileTime)!=int(OtherDerived::RowsAtCompileTime)) + return assign(other.transpose()); + else + return assign(other); + } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + inline SparseVector& operator=(const SparseSparseProduct& product) + { + return Base::operator=(product); + } + #endif + + friend std::ostream & operator << (std::ostream & s, const SparseVector& m) + { + for (Index i=0; i + EIGEN_DONT_INLINE SparseVector& assign(const SparseMatrixBase& _other) + { + const OtherDerived& other(_other.derived()); + const bool needToTranspose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); + if(needToTranspose) + { + Index size = other.size(); + Index nnz = other.nonZeros(); + resize(size); + reserve(nnz); + for(Index i=0; i +class SparseVector::InnerIterator +{ + public: + InnerIterator(const SparseVector& vec, Index outer=0) + : m_data(vec.m_data), m_id(0), m_end(static_cast(m_data.size())) + { + EIGEN_UNUSED_VARIABLE(outer); + eigen_assert(outer==0); + } + + InnerIterator(const internal::CompressedStorage& data) + : m_data(data), m_id(0), m_end(static_cast(m_data.size())) + {} + + inline InnerIterator& operator++() { m_id++; return *this; } + + inline Scalar value() const { return m_data.value(m_id); } + inline Scalar& valueRef() { return const_cast(m_data.value(m_id)); } + + inline Index index() const { return m_data.index(m_id); } + inline Index row() const { return IsColVector ? index() : 0; } + inline Index col() const { return IsColVector ? 0 : index(); } + + inline operator bool() const { return (m_id < m_end); } + + protected: + const internal::CompressedStorage& m_data; + Index m_id; + const Index m_end; +}; + +template +class SparseVector::ReverseInnerIterator +{ + public: + ReverseInnerIterator(const SparseVector& vec, Index outer=0) + : m_data(vec.m_data), m_id(static_cast(m_data.size())), m_start(0) + { + EIGEN_UNUSED_VARIABLE(outer); + eigen_assert(outer==0); + } + + ReverseInnerIterator(const internal::CompressedStorage& data) + : m_data(data), m_id(static_cast(m_data.size())), m_start(0) + {} + + inline ReverseInnerIterator& operator--() { m_id--; return *this; } + + inline Scalar value() const { return m_data.value(m_id-1); } + inline Scalar& valueRef() { return const_cast(m_data.value(m_id-1)); } + + inline Index index() const { return m_data.index(m_id-1); } + inline Index row() const { return IsColVector ? index() : 0; } + inline Index col() const { return IsColVector ? 0 : index(); } + + inline operator bool() const { return (m_id > m_start); } + + protected: + const internal::CompressedStorage& m_data; + Index m_id; + const Index m_start; +}; + +} // end namespace Eigen + +#endif // EIGEN_SPARSEVECTOR_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseView.h b/extern/Eigen3/Eigen/src/SparseCore/SparseView.h new file mode 100644 index 00000000000..8b0b9ea0304 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseView.h @@ -0,0 +1,98 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Gael Guennebaud +// Copyright (C) 2010 Daniel Lowengrub +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSEVIEW_H +#define EIGEN_SPARSEVIEW_H + +namespace Eigen { + +namespace internal { + +template +struct traits > : traits +{ + typedef int Index; + typedef Sparse StorageKind; + enum { + Flags = int(traits::Flags) & (RowMajorBit) + }; +}; + +} // end namespace internal + +template +class SparseView : public SparseMatrixBase > +{ + typedef typename MatrixType::Nested MatrixTypeNested; + typedef typename internal::remove_all::type _MatrixTypeNested; +public: + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseView) + + SparseView(const MatrixType& mat, const Scalar& m_reference = Scalar(0), + typename NumTraits::Real m_epsilon = NumTraits::dummy_precision()) : + m_matrix(mat), m_reference(m_reference), m_epsilon(m_epsilon) {} + + class InnerIterator; + + inline Index rows() const { return m_matrix.rows(); } + inline Index cols() const { return m_matrix.cols(); } + + inline Index innerSize() const { return m_matrix.innerSize(); } + inline Index outerSize() const { return m_matrix.outerSize(); } + +protected: + MatrixTypeNested m_matrix; + Scalar m_reference; + typename NumTraits::Real m_epsilon; +}; + +template +class SparseView::InnerIterator : public _MatrixTypeNested::InnerIterator +{ +public: + typedef typename _MatrixTypeNested::InnerIterator IterBase; + InnerIterator(const SparseView& view, Index outer) : + IterBase(view.m_matrix, outer), m_view(view) + { + incrementToNonZero(); + } + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { + IterBase::operator++(); + incrementToNonZero(); + return *this; + } + + using IterBase::value; + +protected: + const SparseView& m_view; + +private: + void incrementToNonZero() + { + while((bool(*this)) && internal::isMuchSmallerThan(value(), m_view.m_reference, m_view.m_epsilon)) + { + IterBase::operator++(); + } + } +}; + +template +const SparseView MatrixBase::sparseView(const Scalar& m_reference, + typename NumTraits::Real m_epsilon) const +{ + return SparseView(derived(), m_reference, m_epsilon); +} + +} // end namespace Eigen + +#endif diff --git a/extern/Eigen3/Eigen/src/SparseCore/TriangularSolver.h b/extern/Eigen3/Eigen/src/SparseCore/TriangularSolver.h new file mode 100644 index 00000000000..cb8ad82b4f6 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SparseCore/TriangularSolver.h @@ -0,0 +1,334 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSETRIANGULARSOLVER_H +#define EIGEN_SPARSETRIANGULARSOLVER_H + +namespace Eigen { + +namespace internal { + +template::Flags) & RowMajorBit> +struct sparse_solve_triangular_selector; + +// forward substitution, row-major +template +struct sparse_solve_triangular_selector +{ + typedef typename Rhs::Scalar Scalar; + static void run(const Lhs& lhs, Rhs& other) + { + for(int col=0 ; col +struct sparse_solve_triangular_selector +{ + typedef typename Rhs::Scalar Scalar; + static void run(const Lhs& lhs, Rhs& other) + { + for(int col=0 ; col=0 ; --i) + { + Scalar tmp = other.coeff(i,col); + Scalar l_ii = 0; + typename Lhs::InnerIterator it(lhs, i); + while(it && it.index() +struct sparse_solve_triangular_selector +{ + typedef typename Rhs::Scalar Scalar; + static void run(const Lhs& lhs, Rhs& other) + { + for(int col=0 ; col +struct sparse_solve_triangular_selector +{ + typedef typename Rhs::Scalar Scalar; + static void run(const Lhs& lhs, Rhs& other) + { + for(int col=0 ; col=0; --i) + { + Scalar& tmp = other.coeffRef(i,col); + if (tmp!=Scalar(0)) // optimization when other is actually sparse + { + if(!(Mode & UnitDiag)) + { + // TODO replace this by a binary search. make sure the binary search is safe for partially sorted elements + typename Lhs::ReverseInnerIterator it(lhs, i); + while(it && it.index()!=i) + --it; + eigen_assert(it && it.index()==i); + other.coeffRef(i,col) /= it.value(); + } + typename Lhs::InnerIterator it(lhs, i); + for(; it && it.index() +template +void SparseTriangularView::solveInPlace(MatrixBase& other) const +{ + eigen_assert(m_matrix.cols() == m_matrix.rows() && m_matrix.cols() == other.rows()); + eigen_assert((!(Mode & ZeroDiag)) && bool(Mode & (Upper|Lower))); + + enum { copy = internal::traits::Flags & RowMajorBit }; + + typedef typename internal::conditional::type, OtherDerived&>::type OtherCopy; + OtherCopy otherCopy(other.derived()); + + internal::sparse_solve_triangular_selector::type, Mode>::run(m_matrix, otherCopy); + + if (copy) + other = otherCopy; +} + +template +template +typename internal::plain_matrix_type_column_major::type +SparseTriangularView::solve(const MatrixBase& other) const +{ + typename internal::plain_matrix_type_column_major::type res(other); + solveInPlace(res); + return res; +} + +// pure sparse path + +namespace internal { + +template +struct sparse_solve_triangular_sparse_selector; + +// forward substitution, col-major +template +struct sparse_solve_triangular_sparse_selector +{ + typedef typename Rhs::Scalar Scalar; + typedef typename promote_index_type::Index, + typename traits::Index>::type Index; + static void run(const Lhs& lhs, Rhs& other) + { + const bool IsLower = (UpLo==Lower); + AmbiVector tempVector(other.rows()*2); + tempVector.setBounds(0,other.rows()); + + Rhs res(other.rows(), other.cols()); + res.reserve(other.nonZeros()); + + for(int col=0 ; col=0; + i+=IsLower?1:-1) + { + tempVector.restart(); + Scalar& ci = tempVector.coeffRef(i); + if (ci!=Scalar(0)) + { + // find + typename Lhs::InnerIterator it(lhs, i); + if(!(Mode & UnitDiag)) + { + if (IsLower) + { + eigen_assert(it.index()==i); + ci /= it.value(); + } + else + ci /= lhs.coeff(i,i); + } + tempVector.restart(); + if (IsLower) + { + if (it.index()==i) + ++it; + for(; it; ++it) + tempVector.coeffRef(it.index()) -= ci * it.value(); + } + else + { + for(; it && it.index()::Iterator it(tempVector/*,1e-12*/); it; ++it) + { + ++ count; +// std::cerr << "fill " << it.index() << ", " << col << "\n"; +// std::cout << it.value() << " "; + // FIXME use insertBack + res.insert(it.index(), col) = it.value(); + } +// std::cout << "tempVector.nonZeros() == " << int(count) << " / " << (other.rows()) << "\n"; + } + res.finalize(); + other = res.markAsRValue(); + } +}; + +} // end namespace internal + +template +template +void SparseTriangularView::solveInPlace(SparseMatrixBase& other) const +{ + eigen_assert(m_matrix.cols() == m_matrix.rows() && m_matrix.cols() == other.rows()); + eigen_assert( (!(Mode & ZeroDiag)) && bool(Mode & (Upper|Lower))); + +// enum { copy = internal::traits::Flags & RowMajorBit }; + +// typedef typename internal::conditional::type, OtherDerived&>::type OtherCopy; +// OtherCopy otherCopy(other.derived()); + + internal::sparse_solve_triangular_sparse_selector::run(m_matrix, other.derived()); + +// if (copy) +// other = otherCopy; +} + +#ifdef EIGEN2_SUPPORT + +// deprecated stuff: + +/** \deprecated */ +template +template +void SparseMatrixBase::solveTriangularInPlace(MatrixBase& other) const +{ + this->template triangular().solveInPlace(other); +} + +/** \deprecated */ +template +template +typename internal::plain_matrix_type_column_major::type +SparseMatrixBase::solveTriangular(const MatrixBase& other) const +{ + typename internal::plain_matrix_type_column_major::type res(other); + derived().solveTriangularInPlace(res); + return res; +} +#endif // EIGEN2_SUPPORT + +} // end namespace Eigen + +#endif // EIGEN_SPARSETRIANGULARSOLVER_H diff --git a/extern/Eigen3/Eigen/src/StlSupport/StdDeque.h b/extern/Eigen3/Eigen/src/StlSupport/StdDeque.h index 6f12c106dbc..4ee8e5c10a5 100644 --- a/extern/Eigen3/Eigen/src/StlSupport/StdDeque.h +++ b/extern/Eigen3/Eigen/src/StlSupport/StdDeque.h @@ -4,24 +4,9 @@ // Copyright (C) 2009 Gael Guennebaud // Copyright (C) 2009 Hauke Heibel // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_STDDEQUE_H #define EIGEN_STDDEQUE_H diff --git a/extern/Eigen3/Eigen/src/StlSupport/StdList.h b/extern/Eigen3/Eigen/src/StlSupport/StdList.h index d329a0b2dc5..627381ecec0 100644 --- a/extern/Eigen3/Eigen/src/StlSupport/StdList.h +++ b/extern/Eigen3/Eigen/src/StlSupport/StdList.h @@ -3,24 +3,9 @@ // // Copyright (C) 2009 Hauke Heibel // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_STDLIST_H #define EIGEN_STDLIST_H diff --git a/extern/Eigen3/Eigen/src/StlSupport/StdVector.h b/extern/Eigen3/Eigen/src/StlSupport/StdVector.h index 27d6ab539f9..40a9abefa82 100644 --- a/extern/Eigen3/Eigen/src/StlSupport/StdVector.h +++ b/extern/Eigen3/Eigen/src/StlSupport/StdVector.h @@ -4,24 +4,9 @@ // Copyright (C) 2009 Gael Guennebaud // Copyright (C) 2009 Hauke Heibel // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_STDVECTOR_H #define EIGEN_STDVECTOR_H diff --git a/extern/Eigen3/Eigen/src/StlSupport/details.h b/extern/Eigen3/Eigen/src/StlSupport/details.h index 397c8ef8581..d8debc7c4f8 100644 --- a/extern/Eigen3/Eigen/src/StlSupport/details.h +++ b/extern/Eigen3/Eigen/src/StlSupport/details.h @@ -4,24 +4,9 @@ // Copyright (C) 2009 Gael Guennebaud // Copyright (C) 2009 Hauke Heibel // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_STL_DETAILS_H #define EIGEN_STL_DETAILS_H diff --git a/extern/Eigen3/Eigen/src/SuperLUSupport/SuperLUSupport.h b/extern/Eigen3/Eigen/src/SuperLUSupport/SuperLUSupport.h new file mode 100644 index 00000000000..11fb014dd93 --- /dev/null +++ b/extern/Eigen3/Eigen/src/SuperLUSupport/SuperLUSupport.h @@ -0,0 +1,1025 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2011 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SUPERLUSUPPORT_H +#define EIGEN_SUPERLUSUPPORT_H + +namespace Eigen { + +#define DECL_GSSVX(PREFIX,FLOATTYPE,KEYTYPE) \ + extern "C" { \ + typedef struct { FLOATTYPE for_lu; FLOATTYPE total_needed; int expansions; } PREFIX##mem_usage_t; \ + extern void PREFIX##gssvx(superlu_options_t *, SuperMatrix *, int *, int *, int *, \ + char *, FLOATTYPE *, FLOATTYPE *, SuperMatrix *, SuperMatrix *, \ + void *, int, SuperMatrix *, SuperMatrix *, \ + FLOATTYPE *, FLOATTYPE *, FLOATTYPE *, FLOATTYPE *, \ + PREFIX##mem_usage_t *, SuperLUStat_t *, int *); \ + } \ + inline float SuperLU_gssvx(superlu_options_t *options, SuperMatrix *A, \ + int *perm_c, int *perm_r, int *etree, char *equed, \ + FLOATTYPE *R, FLOATTYPE *C, SuperMatrix *L, \ + SuperMatrix *U, void *work, int lwork, \ + SuperMatrix *B, SuperMatrix *X, \ + FLOATTYPE *recip_pivot_growth, \ + FLOATTYPE *rcond, FLOATTYPE *ferr, FLOATTYPE *berr, \ + SuperLUStat_t *stats, int *info, KEYTYPE) { \ + PREFIX##mem_usage_t mem_usage; \ + PREFIX##gssvx(options, A, perm_c, perm_r, etree, equed, R, C, L, \ + U, work, lwork, B, X, recip_pivot_growth, rcond, \ + ferr, berr, &mem_usage, stats, info); \ + return mem_usage.for_lu; /* bytes used by the factor storage */ \ + } + +DECL_GSSVX(s,float,float) +DECL_GSSVX(c,float,std::complex) +DECL_GSSVX(d,double,double) +DECL_GSSVX(z,double,std::complex) + +#ifdef MILU_ALPHA +#define EIGEN_SUPERLU_HAS_ILU +#endif + +#ifdef EIGEN_SUPERLU_HAS_ILU + +// similarly for the incomplete factorization using gsisx +#define DECL_GSISX(PREFIX,FLOATTYPE,KEYTYPE) \ + extern "C" { \ + extern void PREFIX##gsisx(superlu_options_t *, SuperMatrix *, int *, int *, int *, \ + char *, FLOATTYPE *, FLOATTYPE *, SuperMatrix *, SuperMatrix *, \ + void *, int, SuperMatrix *, SuperMatrix *, FLOATTYPE *, FLOATTYPE *, \ + PREFIX##mem_usage_t *, SuperLUStat_t *, int *); \ + } \ + inline float SuperLU_gsisx(superlu_options_t *options, SuperMatrix *A, \ + int *perm_c, int *perm_r, int *etree, char *equed, \ + FLOATTYPE *R, FLOATTYPE *C, SuperMatrix *L, \ + SuperMatrix *U, void *work, int lwork, \ + SuperMatrix *B, SuperMatrix *X, \ + FLOATTYPE *recip_pivot_growth, \ + FLOATTYPE *rcond, \ + SuperLUStat_t *stats, int *info, KEYTYPE) { \ + PREFIX##mem_usage_t mem_usage; \ + PREFIX##gsisx(options, A, perm_c, perm_r, etree, equed, R, C, L, \ + U, work, lwork, B, X, recip_pivot_growth, rcond, \ + &mem_usage, stats, info); \ + return mem_usage.for_lu; /* bytes used by the factor storage */ \ + } + +DECL_GSISX(s,float,float) +DECL_GSISX(c,float,std::complex) +DECL_GSISX(d,double,double) +DECL_GSISX(z,double,std::complex) + +#endif + +template +struct SluMatrixMapHelper; + +/** \internal + * + * A wrapper class for SuperLU matrices. It supports only compressed sparse matrices + * and dense matrices. Supernodal and other fancy format are not supported by this wrapper. + * + * This wrapper class mainly aims to avoids the need of dynamic allocation of the storage structure. + */ +struct SluMatrix : SuperMatrix +{ + SluMatrix() + { + Store = &storage; + } + + SluMatrix(const SluMatrix& other) + : SuperMatrix(other) + { + Store = &storage; + storage = other.storage; + } + + SluMatrix& operator=(const SluMatrix& other) + { + SuperMatrix::operator=(static_cast(other)); + Store = &storage; + storage = other.storage; + return *this; + } + + struct + { + union {int nnz;int lda;}; + void *values; + int *innerInd; + int *outerInd; + } storage; + + void setStorageType(Stype_t t) + { + Stype = t; + if (t==SLU_NC || t==SLU_NR || t==SLU_DN) + Store = &storage; + else + { + eigen_assert(false && "storage type not supported"); + Store = 0; + } + } + + template + void setScalarType() + { + if (internal::is_same::value) + Dtype = SLU_S; + else if (internal::is_same::value) + Dtype = SLU_D; + else if (internal::is_same >::value) + Dtype = SLU_C; + else if (internal::is_same >::value) + Dtype = SLU_Z; + else + { + eigen_assert(false && "Scalar type not supported by SuperLU"); + } + } + + template + static SluMatrix Map(MatrixBase& _mat) + { + MatrixType& mat(_mat.derived()); + eigen_assert( ((MatrixType::Flags&RowMajorBit)!=RowMajorBit) && "row-major dense matrices are not supported by SuperLU"); + SluMatrix res; + res.setStorageType(SLU_DN); + res.setScalarType(); + res.Mtype = SLU_GE; + + res.nrow = mat.rows(); + res.ncol = mat.cols(); + + res.storage.lda = MatrixType::IsVectorAtCompileTime ? mat.size() : mat.outerStride(); + res.storage.values = mat.data(); + return res; + } + + template + static SluMatrix Map(SparseMatrixBase& mat) + { + SluMatrix res; + if ((MatrixType::Flags&RowMajorBit)==RowMajorBit) + { + res.setStorageType(SLU_NR); + res.nrow = mat.cols(); + res.ncol = mat.rows(); + } + else + { + res.setStorageType(SLU_NC); + res.nrow = mat.rows(); + res.ncol = mat.cols(); + } + + res.Mtype = SLU_GE; + + res.storage.nnz = mat.nonZeros(); + res.storage.values = mat.derived().valuePtr(); + res.storage.innerInd = mat.derived().innerIndexPtr(); + res.storage.outerInd = mat.derived().outerIndexPtr(); + + res.setScalarType(); + + // FIXME the following is not very accurate + if (MatrixType::Flags & Upper) + res.Mtype = SLU_TRU; + if (MatrixType::Flags & Lower) + res.Mtype = SLU_TRL; + + eigen_assert(((MatrixType::Flags & SelfAdjoint)==0) && "SelfAdjoint matrix shape not supported by SuperLU"); + + return res; + } +}; + +template +struct SluMatrixMapHelper > +{ + typedef Matrix MatrixType; + static void run(MatrixType& mat, SluMatrix& res) + { + eigen_assert( ((Options&RowMajor)!=RowMajor) && "row-major dense matrices is not supported by SuperLU"); + res.setStorageType(SLU_DN); + res.setScalarType(); + res.Mtype = SLU_GE; + + res.nrow = mat.rows(); + res.ncol = mat.cols(); + + res.storage.lda = mat.outerStride(); + res.storage.values = mat.data(); + } +}; + +template +struct SluMatrixMapHelper > +{ + typedef Derived MatrixType; + static void run(MatrixType& mat, SluMatrix& res) + { + if ((MatrixType::Flags&RowMajorBit)==RowMajorBit) + { + res.setStorageType(SLU_NR); + res.nrow = mat.cols(); + res.ncol = mat.rows(); + } + else + { + res.setStorageType(SLU_NC); + res.nrow = mat.rows(); + res.ncol = mat.cols(); + } + + res.Mtype = SLU_GE; + + res.storage.nnz = mat.nonZeros(); + res.storage.values = mat.valuePtr(); + res.storage.innerInd = mat.innerIndexPtr(); + res.storage.outerInd = mat.outerIndexPtr(); + + res.setScalarType(); + + // FIXME the following is not very accurate + if (MatrixType::Flags & Upper) + res.Mtype = SLU_TRU; + if (MatrixType::Flags & Lower) + res.Mtype = SLU_TRL; + + eigen_assert(((MatrixType::Flags & SelfAdjoint)==0) && "SelfAdjoint matrix shape not supported by SuperLU"); + } +}; + +namespace internal { + +template +SluMatrix asSluMatrix(MatrixType& mat) +{ + return SluMatrix::Map(mat); +} + +/** View a Super LU matrix as an Eigen expression */ +template +MappedSparseMatrix map_superlu(SluMatrix& sluMat) +{ + eigen_assert((Flags&RowMajor)==RowMajor && sluMat.Stype == SLU_NR + || (Flags&ColMajor)==ColMajor && sluMat.Stype == SLU_NC); + + Index outerSize = (Flags&RowMajor)==RowMajor ? sluMat.ncol : sluMat.nrow; + + return MappedSparseMatrix( + sluMat.nrow, sluMat.ncol, sluMat.storage.outerInd[outerSize], + sluMat.storage.outerInd, sluMat.storage.innerInd, reinterpret_cast(sluMat.storage.values) ); +} + +} // end namespace internal + +/** \ingroup SuperLUSupport_Module + * \class SuperLUBase + * \brief The base class for the direct and incomplete LU factorization of SuperLU + */ +template +class SuperLUBase : internal::noncopyable +{ + public: + typedef _MatrixType MatrixType; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + typedef Matrix Vector; + typedef Matrix IntRowVectorType; + typedef Matrix IntColVectorType; + typedef SparseMatrix LUMatrixType; + + public: + + SuperLUBase() {} + + ~SuperLUBase() + { + clearFactors(); + } + + Derived& derived() { return *static_cast(this); } + const Derived& derived() const { return *static_cast(this); } + + inline Index rows() const { return m_matrix.rows(); } + inline Index cols() const { return m_matrix.cols(); } + + /** \returns a reference to the Super LU option object to configure the Super LU algorithms. */ + inline superlu_options_t& options() { return m_sluOptions; } + + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was succesful, + * \c NumericalIssue if the matrix.appears to be negative. + */ + ComputationInfo info() const + { + eigen_assert(m_isInitialized && "Decomposition is not initialized."); + return m_info; + } + + /** Computes the sparse Cholesky decomposition of \a matrix */ + void compute(const MatrixType& matrix) + { + derived().analyzePattern(matrix); + derived().factorize(matrix); + } + + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ + template + inline const internal::solve_retval solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "SuperLU is not initialized."); + eigen_assert(rows()==b.rows() + && "SuperLU::solve(): invalid number of rows of the right hand side matrix b"); + return internal::solve_retval(*this, b.derived()); + } + + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ +// template +// inline const internal::sparse_solve_retval solve(const SparseMatrixBase& b) const +// { +// eigen_assert(m_isInitialized && "SuperLU is not initialized."); +// eigen_assert(rows()==b.rows() +// && "SuperLU::solve(): invalid number of rows of the right hand side matrix b"); +// return internal::sparse_solve_retval(*this, b.derived()); +// } + + /** Performs a symbolic decomposition on the sparcity of \a matrix. + * + * This function is particularly useful when solving for several problems having the same structure. + * + * \sa factorize() + */ + void analyzePattern(const MatrixType& /*matrix*/) + { + m_isInitialized = true; + m_info = Success; + m_analysisIsOk = true; + m_factorizationIsOk = false; + } + + template + void dumpMemory(Stream& s) + {} + + protected: + + void initFactorization(const MatrixType& a) + { + set_default_options(&this->m_sluOptions); + + const int size = a.rows(); + m_matrix = a; + + m_sluA = internal::asSluMatrix(m_matrix); + clearFactors(); + + m_p.resize(size); + m_q.resize(size); + m_sluRscale.resize(size); + m_sluCscale.resize(size); + m_sluEtree.resize(size); + + // set empty B and X + m_sluB.setStorageType(SLU_DN); + m_sluB.setScalarType(); + m_sluB.Mtype = SLU_GE; + m_sluB.storage.values = 0; + m_sluB.nrow = 0; + m_sluB.ncol = 0; + m_sluB.storage.lda = size; + m_sluX = m_sluB; + + m_extractedDataAreDirty = true; + } + + void init() + { + m_info = InvalidInput; + m_isInitialized = false; + m_sluL.Store = 0; + m_sluU.Store = 0; + } + + void extractData() const; + + void clearFactors() + { + if(m_sluL.Store) + Destroy_SuperNode_Matrix(&m_sluL); + if(m_sluU.Store) + Destroy_CompCol_Matrix(&m_sluU); + + m_sluL.Store = 0; + m_sluU.Store = 0; + + memset(&m_sluL,0,sizeof m_sluL); + memset(&m_sluU,0,sizeof m_sluU); + } + + // cached data to reduce reallocation, etc. + mutable LUMatrixType m_l; + mutable LUMatrixType m_u; + mutable IntColVectorType m_p; + mutable IntRowVectorType m_q; + + mutable LUMatrixType m_matrix; // copy of the factorized matrix + mutable SluMatrix m_sluA; + mutable SuperMatrix m_sluL, m_sluU; + mutable SluMatrix m_sluB, m_sluX; + mutable SuperLUStat_t m_sluStat; + mutable superlu_options_t m_sluOptions; + mutable std::vector m_sluEtree; + mutable Matrix m_sluRscale, m_sluCscale; + mutable Matrix m_sluFerr, m_sluBerr; + mutable char m_sluEqued; + + mutable ComputationInfo m_info; + bool m_isInitialized; + int m_factorizationIsOk; + int m_analysisIsOk; + mutable bool m_extractedDataAreDirty; + + private: + SuperLUBase(SuperLUBase& ) { } +}; + + +/** \ingroup SuperLUSupport_Module + * \class SuperLU + * \brief A sparse direct LU factorization and solver based on the SuperLU library + * + * This class allows to solve for A.X = B sparse linear problems via a direct LU factorization + * using the SuperLU library. The sparse matrix A must be squared and invertible. The vectors or matrices + * X and B can be either dense or sparse. + * + * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * + * \sa \ref TutorialSparseDirectSolvers + */ +template +class SuperLU : public SuperLUBase<_MatrixType,SuperLU<_MatrixType> > +{ + public: + typedef SuperLUBase<_MatrixType,SuperLU> Base; + typedef _MatrixType MatrixType; + typedef typename Base::Scalar Scalar; + typedef typename Base::RealScalar RealScalar; + typedef typename Base::Index Index; + typedef typename Base::IntRowVectorType IntRowVectorType; + typedef typename Base::IntColVectorType IntColVectorType; + typedef typename Base::LUMatrixType LUMatrixType; + typedef TriangularView LMatrixType; + typedef TriangularView UMatrixType; + + public: + + SuperLU() : Base() { init(); } + + SuperLU(const MatrixType& matrix) : Base() + { + Base::init(); + compute(matrix); + } + + ~SuperLU() + { + } + + /** Performs a symbolic decomposition on the sparcity of \a matrix. + * + * This function is particularly useful when solving for several problems having the same structure. + * + * \sa factorize() + */ + void analyzePattern(const MatrixType& matrix) + { + m_info = InvalidInput; + m_isInitialized = false; + Base::analyzePattern(matrix); + } + + /** Performs a numeric decomposition of \a matrix + * + * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. + * + * \sa analyzePattern() + */ + void factorize(const MatrixType& matrix); + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal */ + template + void _solve(const MatrixBase &b, MatrixBase &dest) const; + #endif // EIGEN_PARSED_BY_DOXYGEN + + inline const LMatrixType& matrixL() const + { + if (m_extractedDataAreDirty) this->extractData(); + return m_l; + } + + inline const UMatrixType& matrixU() const + { + if (m_extractedDataAreDirty) this->extractData(); + return m_u; + } + + inline const IntColVectorType& permutationP() const + { + if (m_extractedDataAreDirty) this->extractData(); + return m_p; + } + + inline const IntRowVectorType& permutationQ() const + { + if (m_extractedDataAreDirty) this->extractData(); + return m_q; + } + + Scalar determinant() const; + + protected: + + using Base::m_matrix; + using Base::m_sluOptions; + using Base::m_sluA; + using Base::m_sluB; + using Base::m_sluX; + using Base::m_p; + using Base::m_q; + using Base::m_sluEtree; + using Base::m_sluEqued; + using Base::m_sluRscale; + using Base::m_sluCscale; + using Base::m_sluL; + using Base::m_sluU; + using Base::m_sluStat; + using Base::m_sluFerr; + using Base::m_sluBerr; + using Base::m_l; + using Base::m_u; + + using Base::m_analysisIsOk; + using Base::m_factorizationIsOk; + using Base::m_extractedDataAreDirty; + using Base::m_isInitialized; + using Base::m_info; + + void init() + { + Base::init(); + + set_default_options(&this->m_sluOptions); + m_sluOptions.PrintStat = NO; + m_sluOptions.ConditionNumber = NO; + m_sluOptions.Trans = NOTRANS; + m_sluOptions.ColPerm = COLAMD; + } + + + private: + SuperLU(SuperLU& ) { } +}; + +template +void SuperLU::factorize(const MatrixType& a) +{ + eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); + if(!m_analysisIsOk) + { + m_info = InvalidInput; + return; + } + + this->initFactorization(a); + + int info = 0; + RealScalar recip_pivot_growth, rcond; + RealScalar ferr, berr; + + StatInit(&m_sluStat); + SuperLU_gssvx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0], + &m_sluEqued, &m_sluRscale[0], &m_sluCscale[0], + &m_sluL, &m_sluU, + NULL, 0, + &m_sluB, &m_sluX, + &recip_pivot_growth, &rcond, + &ferr, &berr, + &m_sluStat, &info, Scalar()); + StatFree(&m_sluStat); + + m_extractedDataAreDirty = true; + + // FIXME how to better check for errors ??? + m_info = info == 0 ? Success : NumericalIssue; + m_factorizationIsOk = true; +} + +template +template +void SuperLU::_solve(const MatrixBase &b, MatrixBase& x) const +{ + eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or analyzePattern()/factorize()"); + + const int size = m_matrix.rows(); + const int rhsCols = b.cols(); + eigen_assert(size==b.rows()); + + m_sluOptions.Trans = NOTRANS; + m_sluOptions.Fact = FACTORED; + m_sluOptions.IterRefine = NOREFINE; + + + m_sluFerr.resize(rhsCols); + m_sluBerr.resize(rhsCols); + m_sluB = SluMatrix::Map(b.const_cast_derived()); + m_sluX = SluMatrix::Map(x.derived()); + + typename Rhs::PlainObject b_cpy; + if(m_sluEqued!='N') + { + b_cpy = b; + m_sluB = SluMatrix::Map(b_cpy.const_cast_derived()); + } + + StatInit(&m_sluStat); + int info = 0; + RealScalar recip_pivot_growth, rcond; + SuperLU_gssvx(&m_sluOptions, &m_sluA, + m_q.data(), m_p.data(), + &m_sluEtree[0], &m_sluEqued, + &m_sluRscale[0], &m_sluCscale[0], + &m_sluL, &m_sluU, + NULL, 0, + &m_sluB, &m_sluX, + &recip_pivot_growth, &rcond, + &m_sluFerr[0], &m_sluBerr[0], + &m_sluStat, &info, Scalar()); + StatFree(&m_sluStat); + m_info = info==0 ? Success : NumericalIssue; +} + +// the code of this extractData() function has been adapted from the SuperLU's Matlab support code, +// +// Copyright (c) 1994 by Xerox Corporation. All rights reserved. +// +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY +// EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. +// +template +void SuperLUBase::extractData() const +{ + eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for extracting factors, you must first call either compute() or analyzePattern()/factorize()"); + if (m_extractedDataAreDirty) + { + int upper; + int fsupc, istart, nsupr; + int lastl = 0, lastu = 0; + SCformat *Lstore = static_cast(m_sluL.Store); + NCformat *Ustore = static_cast(m_sluU.Store); + Scalar *SNptr; + + const int size = m_matrix.rows(); + m_l.resize(size,size); + m_l.resizeNonZeros(Lstore->nnz); + m_u.resize(size,size); + m_u.resizeNonZeros(Ustore->nnz); + + int* Lcol = m_l.outerIndexPtr(); + int* Lrow = m_l.innerIndexPtr(); + Scalar* Lval = m_l.valuePtr(); + + int* Ucol = m_u.outerIndexPtr(); + int* Urow = m_u.innerIndexPtr(); + Scalar* Uval = m_u.valuePtr(); + + Ucol[0] = 0; + Ucol[0] = 0; + + /* for each supernode */ + for (int k = 0; k <= Lstore->nsuper; ++k) + { + fsupc = L_FST_SUPC(k); + istart = L_SUB_START(fsupc); + nsupr = L_SUB_START(fsupc+1) - istart; + upper = 1; + + /* for each column in the supernode */ + for (int j = fsupc; j < L_FST_SUPC(k+1); ++j) + { + SNptr = &((Scalar*)Lstore->nzval)[L_NZ_START(j)]; + + /* Extract U */ + for (int i = U_NZ_START(j); i < U_NZ_START(j+1); ++i) + { + Uval[lastu] = ((Scalar*)Ustore->nzval)[i]; + /* Matlab doesn't like explicit zero. */ + if (Uval[lastu] != 0.0) + Urow[lastu++] = U_SUB(i); + } + for (int i = 0; i < upper; ++i) + { + /* upper triangle in the supernode */ + Uval[lastu] = SNptr[i]; + /* Matlab doesn't like explicit zero. */ + if (Uval[lastu] != 0.0) + Urow[lastu++] = L_SUB(istart+i); + } + Ucol[j+1] = lastu; + + /* Extract L */ + Lval[lastl] = 1.0; /* unit diagonal */ + Lrow[lastl++] = L_SUB(istart + upper - 1); + for (int i = upper; i < nsupr; ++i) + { + Lval[lastl] = SNptr[i]; + /* Matlab doesn't like explicit zero. */ + if (Lval[lastl] != 0.0) + Lrow[lastl++] = L_SUB(istart+i); + } + Lcol[j+1] = lastl; + + ++upper; + } /* for j ... */ + + } /* for k ... */ + + // squeeze the matrices : + m_l.resizeNonZeros(lastl); + m_u.resizeNonZeros(lastu); + + m_extractedDataAreDirty = false; + } +} + +template +typename SuperLU::Scalar SuperLU::determinant() const +{ + eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for computing the determinant, you must first call either compute() or analyzePattern()/factorize()"); + + if (m_extractedDataAreDirty) + this->extractData(); + + Scalar det = Scalar(1); + for (int j=0; j 0) + { + int lastId = m_u.outerIndexPtr()[j+1]-1; + eigen_assert(m_u.innerIndexPtr()[lastId]<=j); + if (m_u.innerIndexPtr()[lastId]==j) + det *= m_u.valuePtr()[lastId]; + } + } + if(m_sluEqued!='N') + return det/m_sluRscale.prod()/m_sluCscale.prod(); + else + return det; +} + +#ifdef EIGEN_PARSED_BY_DOXYGEN +#define EIGEN_SUPERLU_HAS_ILU +#endif + +#ifdef EIGEN_SUPERLU_HAS_ILU + +/** \ingroup SuperLUSupport_Module + * \class SuperILU + * \brief A sparse direct \b incomplete LU factorization and solver based on the SuperLU library + * + * This class allows to solve for an approximate solution of A.X = B sparse linear problems via an incomplete LU factorization + * using the SuperLU library. This class is aimed to be used as a preconditioner of the iterative linear solvers. + * + * \warning This class requires SuperLU 4 or later. + * + * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * + * \sa \ref TutorialSparseDirectSolvers, class ConjugateGradient, class BiCGSTAB + */ + +template +class SuperILU : public SuperLUBase<_MatrixType,SuperILU<_MatrixType> > +{ + public: + typedef SuperLUBase<_MatrixType,SuperILU> Base; + typedef _MatrixType MatrixType; + typedef typename Base::Scalar Scalar; + typedef typename Base::RealScalar RealScalar; + typedef typename Base::Index Index; + + public: + + SuperILU() : Base() { init(); } + + SuperILU(const MatrixType& matrix) : Base() + { + init(); + compute(matrix); + } + + ~SuperILU() + { + } + + /** Performs a symbolic decomposition on the sparcity of \a matrix. + * + * This function is particularly useful when solving for several problems having the same structure. + * + * \sa factorize() + */ + void analyzePattern(const MatrixType& matrix) + { + Base::analyzePattern(matrix); + } + + /** Performs a numeric decomposition of \a matrix + * + * The given matrix must has the same sparcity than the matrix on which the symbolic decomposition has been performed. + * + * \sa analyzePattern() + */ + void factorize(const MatrixType& matrix); + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal */ + template + void _solve(const MatrixBase &b, MatrixBase &dest) const; + #endif // EIGEN_PARSED_BY_DOXYGEN + + protected: + + using Base::m_matrix; + using Base::m_sluOptions; + using Base::m_sluA; + using Base::m_sluB; + using Base::m_sluX; + using Base::m_p; + using Base::m_q; + using Base::m_sluEtree; + using Base::m_sluEqued; + using Base::m_sluRscale; + using Base::m_sluCscale; + using Base::m_sluL; + using Base::m_sluU; + using Base::m_sluStat; + using Base::m_sluFerr; + using Base::m_sluBerr; + using Base::m_l; + using Base::m_u; + + using Base::m_analysisIsOk; + using Base::m_factorizationIsOk; + using Base::m_extractedDataAreDirty; + using Base::m_isInitialized; + using Base::m_info; + + void init() + { + Base::init(); + + ilu_set_default_options(&m_sluOptions); + m_sluOptions.PrintStat = NO; + m_sluOptions.ConditionNumber = NO; + m_sluOptions.Trans = NOTRANS; + m_sluOptions.ColPerm = MMD_AT_PLUS_A; + + // no attempt to preserve column sum + m_sluOptions.ILU_MILU = SILU; + // only basic ILU(k) support -- no direct control over memory consumption + // better to use ILU_DropRule = DROP_BASIC | DROP_AREA + // and set ILU_FillFactor to max memory growth + m_sluOptions.ILU_DropRule = DROP_BASIC; + m_sluOptions.ILU_DropTol = NumTraits::dummy_precision()*10; + } + + private: + SuperILU(SuperILU& ) { } +}; + +template +void SuperILU::factorize(const MatrixType& a) +{ + eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); + if(!m_analysisIsOk) + { + m_info = InvalidInput; + return; + } + + this->initFactorization(a); + + int info = 0; + RealScalar recip_pivot_growth, rcond; + + StatInit(&m_sluStat); + SuperLU_gsisx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0], + &m_sluEqued, &m_sluRscale[0], &m_sluCscale[0], + &m_sluL, &m_sluU, + NULL, 0, + &m_sluB, &m_sluX, + &recip_pivot_growth, &rcond, + &m_sluStat, &info, Scalar()); + StatFree(&m_sluStat); + + // FIXME how to better check for errors ??? + m_info = info == 0 ? Success : NumericalIssue; + m_factorizationIsOk = true; +} + +template +template +void SuperILU::_solve(const MatrixBase &b, MatrixBase& x) const +{ + eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or analyzePattern()/factorize()"); + + const int size = m_matrix.rows(); + const int rhsCols = b.cols(); + eigen_assert(size==b.rows()); + + m_sluOptions.Trans = NOTRANS; + m_sluOptions.Fact = FACTORED; + m_sluOptions.IterRefine = NOREFINE; + + m_sluFerr.resize(rhsCols); + m_sluBerr.resize(rhsCols); + m_sluB = SluMatrix::Map(b.const_cast_derived()); + m_sluX = SluMatrix::Map(x.derived()); + + typename Rhs::PlainObject b_cpy; + if(m_sluEqued!='N') + { + b_cpy = b; + m_sluB = SluMatrix::Map(b_cpy.const_cast_derived()); + } + + int info = 0; + RealScalar recip_pivot_growth, rcond; + + StatInit(&m_sluStat); + SuperLU_gsisx(&m_sluOptions, &m_sluA, + m_q.data(), m_p.data(), + &m_sluEtree[0], &m_sluEqued, + &m_sluRscale[0], &m_sluCscale[0], + &m_sluL, &m_sluU, + NULL, 0, + &m_sluB, &m_sluX, + &recip_pivot_growth, &rcond, + &m_sluStat, &info, Scalar()); + StatFree(&m_sluStat); + + m_info = info==0 ? Success : NumericalIssue; +} +#endif + +namespace internal { + +template +struct solve_retval, Rhs> + : solve_retval_base, Rhs> +{ + typedef SuperLUBase<_MatrixType,Derived> Dec; + EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec().derived()._solve(rhs(),dst); + } +}; + +template +struct sparse_solve_retval, Rhs> + : sparse_solve_retval_base, Rhs> +{ + typedef SuperLUBase<_MatrixType,Derived> Dec; + EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec().derived()._solve(rhs(),dst); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_SUPERLUSUPPORT_H diff --git a/extern/Eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h b/extern/Eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h new file mode 100644 index 00000000000..f01720362de --- /dev/null +++ b/extern/Eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h @@ -0,0 +1,431 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2011 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_UMFPACKSUPPORT_H +#define EIGEN_UMFPACKSUPPORT_H + +namespace Eigen { + +/* TODO extract L, extract U, compute det, etc... */ + +// generic double/complex wrapper functions: + +inline void umfpack_free_numeric(void **Numeric, double) +{ umfpack_di_free_numeric(Numeric); *Numeric = 0; } + +inline void umfpack_free_numeric(void **Numeric, std::complex) +{ umfpack_zi_free_numeric(Numeric); *Numeric = 0; } + +inline void umfpack_free_symbolic(void **Symbolic, double) +{ umfpack_di_free_symbolic(Symbolic); *Symbolic = 0; } + +inline void umfpack_free_symbolic(void **Symbolic, std::complex) +{ umfpack_zi_free_symbolic(Symbolic); *Symbolic = 0; } + +inline int umfpack_symbolic(int n_row,int n_col, + const int Ap[], const int Ai[], const double Ax[], void **Symbolic, + const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO]) +{ + return umfpack_di_symbolic(n_row,n_col,Ap,Ai,Ax,Symbolic,Control,Info); +} + +inline int umfpack_symbolic(int n_row,int n_col, + const int Ap[], const int Ai[], const std::complex Ax[], void **Symbolic, + const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO]) +{ + return umfpack_zi_symbolic(n_row,n_col,Ap,Ai,&internal::real_ref(Ax[0]),0,Symbolic,Control,Info); +} + +inline int umfpack_numeric( const int Ap[], const int Ai[], const double Ax[], + void *Symbolic, void **Numeric, + const double Control[UMFPACK_CONTROL],double Info [UMFPACK_INFO]) +{ + return umfpack_di_numeric(Ap,Ai,Ax,Symbolic,Numeric,Control,Info); +} + +inline int umfpack_numeric( const int Ap[], const int Ai[], const std::complex Ax[], + void *Symbolic, void **Numeric, + const double Control[UMFPACK_CONTROL],double Info [UMFPACK_INFO]) +{ + return umfpack_zi_numeric(Ap,Ai,&internal::real_ref(Ax[0]),0,Symbolic,Numeric,Control,Info); +} + +inline int umfpack_solve( int sys, const int Ap[], const int Ai[], const double Ax[], + double X[], const double B[], void *Numeric, + const double Control[UMFPACK_CONTROL], double Info[UMFPACK_INFO]) +{ + return umfpack_di_solve(sys,Ap,Ai,Ax,X,B,Numeric,Control,Info); +} + +inline int umfpack_solve( int sys, const int Ap[], const int Ai[], const std::complex Ax[], + std::complex X[], const std::complex B[], void *Numeric, + const double Control[UMFPACK_CONTROL], double Info[UMFPACK_INFO]) +{ + return umfpack_zi_solve(sys,Ap,Ai,&internal::real_ref(Ax[0]),0,&internal::real_ref(X[0]),0,&internal::real_ref(B[0]),0,Numeric,Control,Info); +} + +inline int umfpack_get_lunz(int *lnz, int *unz, int *n_row, int *n_col, int *nz_udiag, void *Numeric, double) +{ + return umfpack_di_get_lunz(lnz,unz,n_row,n_col,nz_udiag,Numeric); +} + +inline int umfpack_get_lunz(int *lnz, int *unz, int *n_row, int *n_col, int *nz_udiag, void *Numeric, std::complex) +{ + return umfpack_zi_get_lunz(lnz,unz,n_row,n_col,nz_udiag,Numeric); +} + +inline int umfpack_get_numeric(int Lp[], int Lj[], double Lx[], int Up[], int Ui[], double Ux[], + int P[], int Q[], double Dx[], int *do_recip, double Rs[], void *Numeric) +{ + return umfpack_di_get_numeric(Lp,Lj,Lx,Up,Ui,Ux,P,Q,Dx,do_recip,Rs,Numeric); +} + +inline int umfpack_get_numeric(int Lp[], int Lj[], std::complex Lx[], int Up[], int Ui[], std::complex Ux[], + int P[], int Q[], std::complex Dx[], int *do_recip, double Rs[], void *Numeric) +{ + double& lx0_real = internal::real_ref(Lx[0]); + double& ux0_real = internal::real_ref(Ux[0]); + double& dx0_real = internal::real_ref(Dx[0]); + return umfpack_zi_get_numeric(Lp,Lj,Lx?&lx0_real:0,0,Up,Ui,Ux?&ux0_real:0,0,P,Q, + Dx?&dx0_real:0,0,do_recip,Rs,Numeric); +} + +inline int umfpack_get_determinant(double *Mx, double *Ex, void *NumericHandle, double User_Info [UMFPACK_INFO]) +{ + return umfpack_di_get_determinant(Mx,Ex,NumericHandle,User_Info); +} + +inline int umfpack_get_determinant(std::complex *Mx, double *Ex, void *NumericHandle, double User_Info [UMFPACK_INFO]) +{ + double& mx_real = internal::real_ref(*Mx); + return umfpack_zi_get_determinant(&mx_real,0,Ex,NumericHandle,User_Info); +} + +/** \ingroup UmfPackSupport_Module + * \brief A sparse LU factorization and solver based on UmfPack + * + * This class allows to solve for A.X = B sparse linear problems via a LU factorization + * using the UmfPack library. The sparse matrix A must be squared and full rank. + * The vectors or matrices X and B can be either dense or sparse. + * + * \WARNING The input matrix A should be in a \b compressed and \b column-major form. + * Otherwise an expensive copy will be made. You can call the inexpensive makeCompressed() to get a compressed matrix. + * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * + * \sa \ref TutorialSparseDirectSolvers + */ +template +class UmfPackLU : internal::noncopyable +{ + public: + typedef _MatrixType MatrixType; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + typedef Matrix Vector; + typedef Matrix IntRowVectorType; + typedef Matrix IntColVectorType; + typedef SparseMatrix LUMatrixType; + typedef SparseMatrix UmfpackMatrixType; + + public: + + UmfPackLU() { init(); } + + UmfPackLU(const MatrixType& matrix) + { + init(); + compute(matrix); + } + + ~UmfPackLU() + { + if(m_symbolic) umfpack_free_symbolic(&m_symbolic,Scalar()); + if(m_numeric) umfpack_free_numeric(&m_numeric,Scalar()); + } + + inline Index rows() const { return m_copyMatrix.rows(); } + inline Index cols() const { return m_copyMatrix.cols(); } + + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was succesful, + * \c NumericalIssue if the matrix.appears to be negative. + */ + ComputationInfo info() const + { + eigen_assert(m_isInitialized && "Decomposition is not initialized."); + return m_info; + } + + inline const LUMatrixType& matrixL() const + { + if (m_extractedDataAreDirty) extractData(); + return m_l; + } + + inline const LUMatrixType& matrixU() const + { + if (m_extractedDataAreDirty) extractData(); + return m_u; + } + + inline const IntColVectorType& permutationP() const + { + if (m_extractedDataAreDirty) extractData(); + return m_p; + } + + inline const IntRowVectorType& permutationQ() const + { + if (m_extractedDataAreDirty) extractData(); + return m_q; + } + + /** Computes the sparse Cholesky decomposition of \a matrix + * Note that the matrix should be column-major, and in compressed format for best performance. + * \sa SparseMatrix::makeCompressed(). + */ + void compute(const MatrixType& matrix) + { + analyzePattern(matrix); + factorize(matrix); + } + + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ + template + inline const internal::solve_retval solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "UmfPackLU is not initialized."); + eigen_assert(rows()==b.rows() + && "UmfPackLU::solve(): invalid number of rows of the right hand side matrix b"); + return internal::solve_retval(*this, b.derived()); + } + + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ +// template +// inline const internal::sparse_solve_retval solve(const SparseMatrixBase& b) const +// { +// eigen_assert(m_isInitialized && "UmfPAckLU is not initialized."); +// eigen_assert(rows()==b.rows() +// && "UmfPAckLU::solve(): invalid number of rows of the right hand side matrix b"); +// return internal::sparse_solve_retval(*this, b.derived()); +// } + + /** Performs a symbolic decomposition on the sparcity of \a matrix. + * + * This function is particularly useful when solving for several problems having the same structure. + * + * \sa factorize(), compute() + */ + void analyzePattern(const MatrixType& matrix) + { + if(m_symbolic) + umfpack_free_symbolic(&m_symbolic,Scalar()); + if(m_numeric) + umfpack_free_numeric(&m_numeric,Scalar()); + + grapInput(matrix); + + int errorCode = 0; + errorCode = umfpack_symbolic(matrix.rows(), matrix.cols(), m_outerIndexPtr, m_innerIndexPtr, m_valuePtr, + &m_symbolic, 0, 0); + + m_isInitialized = true; + m_info = errorCode ? InvalidInput : Success; + m_analysisIsOk = true; + m_factorizationIsOk = false; + } + + /** Performs a numeric decomposition of \a matrix + * + * The given matrix must has the same sparcity than the matrix on which the pattern anylysis has been performed. + * + * \sa analyzePattern(), compute() + */ + void factorize(const MatrixType& matrix) + { + eigen_assert(m_analysisIsOk && "UmfPackLU: you must first call analyzePattern()"); + if(m_numeric) + umfpack_free_numeric(&m_numeric,Scalar()); + + grapInput(matrix); + + int errorCode; + errorCode = umfpack_numeric(m_outerIndexPtr, m_innerIndexPtr, m_valuePtr, + m_symbolic, &m_numeric, 0, 0); + + m_info = errorCode ? NumericalIssue : Success; + m_factorizationIsOk = true; + } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal */ + template + bool _solve(const MatrixBase &b, MatrixBase &x) const; + #endif + + Scalar determinant() const; + + void extractData() const; + + protected: + + + void init() + { + m_info = InvalidInput; + m_isInitialized = false; + m_numeric = 0; + m_symbolic = 0; + m_outerIndexPtr = 0; + m_innerIndexPtr = 0; + m_valuePtr = 0; + } + + void grapInput(const MatrixType& mat) + { + m_copyMatrix.resize(mat.rows(), mat.cols()); + if( ((MatrixType::Flags&RowMajorBit)==RowMajorBit) || sizeof(typename MatrixType::Index)!=sizeof(int) || !mat.isCompressed() ) + { + // non supported input -> copy + m_copyMatrix = mat; + m_outerIndexPtr = m_copyMatrix.outerIndexPtr(); + m_innerIndexPtr = m_copyMatrix.innerIndexPtr(); + m_valuePtr = m_copyMatrix.valuePtr(); + } + else + { + m_outerIndexPtr = mat.outerIndexPtr(); + m_innerIndexPtr = mat.innerIndexPtr(); + m_valuePtr = mat.valuePtr(); + } + } + + // cached data to reduce reallocation, etc. + mutable LUMatrixType m_l; + mutable LUMatrixType m_u; + mutable IntColVectorType m_p; + mutable IntRowVectorType m_q; + + UmfpackMatrixType m_copyMatrix; + const Scalar* m_valuePtr; + const int* m_outerIndexPtr; + const int* m_innerIndexPtr; + void* m_numeric; + void* m_symbolic; + + mutable ComputationInfo m_info; + bool m_isInitialized; + int m_factorizationIsOk; + int m_analysisIsOk; + mutable bool m_extractedDataAreDirty; + + private: + UmfPackLU(UmfPackLU& ) { } +}; + + +template +void UmfPackLU::extractData() const +{ + if (m_extractedDataAreDirty) + { + // get size of the data + int lnz, unz, rows, cols, nz_udiag; + umfpack_get_lunz(&lnz, &unz, &rows, &cols, &nz_udiag, m_numeric, Scalar()); + + // allocate data + m_l.resize(rows,(std::min)(rows,cols)); + m_l.resizeNonZeros(lnz); + + m_u.resize((std::min)(rows,cols),cols); + m_u.resizeNonZeros(unz); + + m_p.resize(rows); + m_q.resize(cols); + + // extract + umfpack_get_numeric(m_l.outerIndexPtr(), m_l.innerIndexPtr(), m_l.valuePtr(), + m_u.outerIndexPtr(), m_u.innerIndexPtr(), m_u.valuePtr(), + m_p.data(), m_q.data(), 0, 0, 0, m_numeric); + + m_extractedDataAreDirty = false; + } +} + +template +typename UmfPackLU::Scalar UmfPackLU::determinant() const +{ + Scalar det; + umfpack_get_determinant(&det, 0, m_numeric, 0); + return det; +} + +template +template +bool UmfPackLU::_solve(const MatrixBase &b, MatrixBase &x) const +{ + const int rhsCols = b.cols(); + eigen_assert((BDerived::Flags&RowMajorBit)==0 && "UmfPackLU backend does not support non col-major rhs yet"); + eigen_assert((XDerived::Flags&RowMajorBit)==0 && "UmfPackLU backend does not support non col-major result yet"); + + int errorCode; + for (int j=0; j +struct solve_retval, Rhs> + : solve_retval_base, Rhs> +{ + typedef UmfPackLU<_MatrixType> Dec; + EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec()._solve(rhs(),dst); + } +}; + +template +struct sparse_solve_retval, Rhs> + : sparse_solve_retval_base, Rhs> +{ + typedef UmfPackLU<_MatrixType> Dec; + EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) + + template void evalTo(Dest& dst) const + { + dec()._solve(rhs(),dst); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_UMFPACKSUPPORT_H diff --git a/extern/Eigen3/Eigen/src/misc/Image.h b/extern/Eigen3/Eigen/src/misc/Image.h index 19b3e08cbfd..75c5f433a8a 100644 --- a/extern/Eigen3/Eigen/src/misc/Image.h +++ b/extern/Eigen3/Eigen/src/misc/Image.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MISC_IMAGE_H #define EIGEN_MISC_IMAGE_H +namespace Eigen { + namespace internal { /** \class image_retval_base @@ -92,4 +79,6 @@ template struct image_retval_base image_retval(const DecompositionType& dec, const MatrixType& originalMatrix) \ : Base(dec, originalMatrix) {} +} // end namespace Eigen + #endif // EIGEN_MISC_IMAGE_H diff --git a/extern/Eigen3/Eigen/src/misc/Kernel.h b/extern/Eigen3/Eigen/src/misc/Kernel.h index 0115970e8eb..b9e1518fd49 100644 --- a/extern/Eigen3/Eigen/src/misc/Kernel.h +++ b/extern/Eigen3/Eigen/src/misc/Kernel.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MISC_KERNEL_H #define EIGEN_MISC_KERNEL_H +namespace Eigen { + namespace internal { /** \class kernel_retval_base @@ -89,4 +76,6 @@ template struct kernel_retval_base using Base::cols; \ kernel_retval(const DecompositionType& dec) : Base(dec) {} +} // end namespace Eigen + #endif // EIGEN_MISC_KERNEL_H diff --git a/extern/Eigen3/Eigen/src/misc/Solve.h b/extern/Eigen3/Eigen/src/misc/Solve.h index b7cbcadb392..7f70d60afbd 100644 --- a/extern/Eigen3/Eigen/src/misc/Solve.h +++ b/extern/Eigen3/Eigen/src/misc/Solve.h @@ -3,28 +3,15 @@ // // Copyright (C) 2009 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MISC_SOLVE_H #define EIGEN_MISC_SOLVE_H +namespace Eigen { + namespace internal { /** \class solve_retval_base @@ -66,7 +53,7 @@ template struct solve_retval_base protected: const DecompositionType& m_dec; - const typename Rhs::Nested m_rhs; + typename Rhs::Nested m_rhs; }; } // end namespace internal @@ -84,4 +71,6 @@ template struct solve_retval_base solve_retval(const DecompositionType& dec, const Rhs& rhs) \ : Base(dec, rhs) {} +} // end namespace Eigen + #endif // EIGEN_MISC_SOLVE_H diff --git a/extern/Eigen3/Eigen/src/misc/SparseSolve.h b/extern/Eigen3/Eigen/src/misc/SparseSolve.h new file mode 100644 index 00000000000..272c4a479d7 --- /dev/null +++ b/extern/Eigen3/Eigen/src/misc/SparseSolve.h @@ -0,0 +1,111 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSE_SOLVE_H +#define EIGEN_SPARSE_SOLVE_H + +namespace Eigen { + +namespace internal { + +template struct sparse_solve_retval_base; +template struct sparse_solve_retval; + +template +struct traits > +{ + typedef typename DecompositionType::MatrixType MatrixType; + typedef SparseMatrix ReturnType; +}; + +template struct sparse_solve_retval_base + : public ReturnByValue > +{ + typedef typename remove_all::type RhsNestedCleaned; + typedef _DecompositionType DecompositionType; + typedef ReturnByValue Base; + typedef typename Base::Index Index; + + sparse_solve_retval_base(const DecompositionType& dec, const Rhs& rhs) + : m_dec(dec), m_rhs(rhs) + {} + + inline Index rows() const { return m_dec.cols(); } + inline Index cols() const { return m_rhs.cols(); } + inline const DecompositionType& dec() const { return m_dec; } + inline const RhsNestedCleaned& rhs() const { return m_rhs; } + + template inline void evalTo(Dest& dst) const + { + static_cast*>(this)->evalTo(dst); + } + + protected: + const DecompositionType& m_dec; + typename Rhs::Nested m_rhs; +}; + +#define EIGEN_MAKE_SPARSE_SOLVE_HELPERS(DecompositionType,Rhs) \ + typedef typename DecompositionType::MatrixType MatrixType; \ + typedef typename MatrixType::Scalar Scalar; \ + typedef typename MatrixType::RealScalar RealScalar; \ + typedef typename MatrixType::Index Index; \ + typedef Eigen::internal::sparse_solve_retval_base Base; \ + using Base::dec; \ + using Base::rhs; \ + using Base::rows; \ + using Base::cols; \ + sparse_solve_retval(const DecompositionType& dec, const Rhs& rhs) \ + : Base(dec, rhs) {} + + + +template struct solve_retval_with_guess; + +template +struct traits > +{ + typedef typename DecompositionType::MatrixType MatrixType; + typedef Matrix ReturnType; +}; + +template struct solve_retval_with_guess + : public ReturnByValue > +{ + typedef typename DecompositionType::Index Index; + + solve_retval_with_guess(const DecompositionType& dec, const Rhs& rhs, const Guess& guess) + : m_dec(dec), m_rhs(rhs), m_guess(guess) + {} + + inline Index rows() const { return m_dec.cols(); } + inline Index cols() const { return m_rhs.cols(); } + + template inline void evalTo(Dest& dst) const + { + dst = m_guess; + m_dec._solveWithGuess(m_rhs,dst); + } + + protected: + const DecompositionType& m_dec; + const typename Rhs::Nested m_rhs; + const typename Guess::Nested m_guess; +}; + +} // namepsace internal + +} // end namespace Eigen + +#endif // EIGEN_SPARSE_SOLVE_H diff --git a/extern/Eigen3/Eigen/src/misc/blas.h b/extern/Eigen3/Eigen/src/misc/blas.h new file mode 100644 index 00000000000..6fce99ed5c4 --- /dev/null +++ b/extern/Eigen3/Eigen/src/misc/blas.h @@ -0,0 +1,658 @@ +#ifndef BLAS_H +#define BLAS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define BLASFUNC(FUNC) FUNC##_ + +#ifdef __WIN64__ +typedef long long BLASLONG; +typedef unsigned long long BLASULONG; +#else +typedef long BLASLONG; +typedef unsigned long BLASULONG; +#endif + +int BLASFUNC(xerbla)(const char *, int *info, int); + +float BLASFUNC(sdot) (int *, float *, int *, float *, int *); +float BLASFUNC(sdsdot)(int *, float *, float *, int *, float *, int *); + +double BLASFUNC(dsdot) (int *, float *, int *, float *, int *); +double BLASFUNC(ddot) (int *, double *, int *, double *, int *); +double BLASFUNC(qdot) (int *, double *, int *, double *, int *); + +int BLASFUNC(cdotuw) (int *, float *, int *, float *, int *, float*); +int BLASFUNC(cdotcw) (int *, float *, int *, float *, int *, float*); +int BLASFUNC(zdotuw) (int *, double *, int *, double *, int *, double*); +int BLASFUNC(zdotcw) (int *, double *, int *, double *, int *, double*); + +int BLASFUNC(saxpy) (int *, float *, float *, int *, float *, int *); +int BLASFUNC(daxpy) (int *, double *, double *, int *, double *, int *); +int BLASFUNC(qaxpy) (int *, double *, double *, int *, double *, int *); +int BLASFUNC(caxpy) (int *, float *, float *, int *, float *, int *); +int BLASFUNC(zaxpy) (int *, double *, double *, int *, double *, int *); +int BLASFUNC(xaxpy) (int *, double *, double *, int *, double *, int *); +int BLASFUNC(caxpyc)(int *, float *, float *, int *, float *, int *); +int BLASFUNC(zaxpyc)(int *, double *, double *, int *, double *, int *); +int BLASFUNC(xaxpyc)(int *, double *, double *, int *, double *, int *); + +int BLASFUNC(scopy) (int *, float *, int *, float *, int *); +int BLASFUNC(dcopy) (int *, double *, int *, double *, int *); +int BLASFUNC(qcopy) (int *, double *, int *, double *, int *); +int BLASFUNC(ccopy) (int *, float *, int *, float *, int *); +int BLASFUNC(zcopy) (int *, double *, int *, double *, int *); +int BLASFUNC(xcopy) (int *, double *, int *, double *, int *); + +int BLASFUNC(sswap) (int *, float *, int *, float *, int *); +int BLASFUNC(dswap) (int *, double *, int *, double *, int *); +int BLASFUNC(qswap) (int *, double *, int *, double *, int *); +int BLASFUNC(cswap) (int *, float *, int *, float *, int *); +int BLASFUNC(zswap) (int *, double *, int *, double *, int *); +int BLASFUNC(xswap) (int *, double *, int *, double *, int *); + +float BLASFUNC(sasum) (int *, float *, int *); +float BLASFUNC(scasum)(int *, float *, int *); +double BLASFUNC(dasum) (int *, double *, int *); +double BLASFUNC(qasum) (int *, double *, int *); +double BLASFUNC(dzasum)(int *, double *, int *); +double BLASFUNC(qxasum)(int *, double *, int *); + +int BLASFUNC(isamax)(int *, float *, int *); +int BLASFUNC(idamax)(int *, double *, int *); +int BLASFUNC(iqamax)(int *, double *, int *); +int BLASFUNC(icamax)(int *, float *, int *); +int BLASFUNC(izamax)(int *, double *, int *); +int BLASFUNC(ixamax)(int *, double *, int *); + +int BLASFUNC(ismax) (int *, float *, int *); +int BLASFUNC(idmax) (int *, double *, int *); +int BLASFUNC(iqmax) (int *, double *, int *); +int BLASFUNC(icmax) (int *, float *, int *); +int BLASFUNC(izmax) (int *, double *, int *); +int BLASFUNC(ixmax) (int *, double *, int *); + +int BLASFUNC(isamin)(int *, float *, int *); +int BLASFUNC(idamin)(int *, double *, int *); +int BLASFUNC(iqamin)(int *, double *, int *); +int BLASFUNC(icamin)(int *, float *, int *); +int BLASFUNC(izamin)(int *, double *, int *); +int BLASFUNC(ixamin)(int *, double *, int *); + +int BLASFUNC(ismin)(int *, float *, int *); +int BLASFUNC(idmin)(int *, double *, int *); +int BLASFUNC(iqmin)(int *, double *, int *); +int BLASFUNC(icmin)(int *, float *, int *); +int BLASFUNC(izmin)(int *, double *, int *); +int BLASFUNC(ixmin)(int *, double *, int *); + +float BLASFUNC(samax) (int *, float *, int *); +double BLASFUNC(damax) (int *, double *, int *); +double BLASFUNC(qamax) (int *, double *, int *); +float BLASFUNC(scamax)(int *, float *, int *); +double BLASFUNC(dzamax)(int *, double *, int *); +double BLASFUNC(qxamax)(int *, double *, int *); + +float BLASFUNC(samin) (int *, float *, int *); +double BLASFUNC(damin) (int *, double *, int *); +double BLASFUNC(qamin) (int *, double *, int *); +float BLASFUNC(scamin)(int *, float *, int *); +double BLASFUNC(dzamin)(int *, double *, int *); +double BLASFUNC(qxamin)(int *, double *, int *); + +float BLASFUNC(smax) (int *, float *, int *); +double BLASFUNC(dmax) (int *, double *, int *); +double BLASFUNC(qmax) (int *, double *, int *); +float BLASFUNC(scmax) (int *, float *, int *); +double BLASFUNC(dzmax) (int *, double *, int *); +double BLASFUNC(qxmax) (int *, double *, int *); + +float BLASFUNC(smin) (int *, float *, int *); +double BLASFUNC(dmin) (int *, double *, int *); +double BLASFUNC(qmin) (int *, double *, int *); +float BLASFUNC(scmin) (int *, float *, int *); +double BLASFUNC(dzmin) (int *, double *, int *); +double BLASFUNC(qxmin) (int *, double *, int *); + +int BLASFUNC(sscal) (int *, float *, float *, int *); +int BLASFUNC(dscal) (int *, double *, double *, int *); +int BLASFUNC(qscal) (int *, double *, double *, int *); +int BLASFUNC(cscal) (int *, float *, float *, int *); +int BLASFUNC(zscal) (int *, double *, double *, int *); +int BLASFUNC(xscal) (int *, double *, double *, int *); +int BLASFUNC(csscal)(int *, float *, float *, int *); +int BLASFUNC(zdscal)(int *, double *, double *, int *); +int BLASFUNC(xqscal)(int *, double *, double *, int *); + +float BLASFUNC(snrm2) (int *, float *, int *); +float BLASFUNC(scnrm2)(int *, float *, int *); + +double BLASFUNC(dnrm2) (int *, double *, int *); +double BLASFUNC(qnrm2) (int *, double *, int *); +double BLASFUNC(dznrm2)(int *, double *, int *); +double BLASFUNC(qxnrm2)(int *, double *, int *); + +int BLASFUNC(srot) (int *, float *, int *, float *, int *, float *, float *); +int BLASFUNC(drot) (int *, double *, int *, double *, int *, double *, double *); +int BLASFUNC(qrot) (int *, double *, int *, double *, int *, double *, double *); +int BLASFUNC(csrot) (int *, float *, int *, float *, int *, float *, float *); +int BLASFUNC(zdrot) (int *, double *, int *, double *, int *, double *, double *); +int BLASFUNC(xqrot) (int *, double *, int *, double *, int *, double *, double *); + +int BLASFUNC(srotg) (float *, float *, float *, float *); +int BLASFUNC(drotg) (double *, double *, double *, double *); +int BLASFUNC(qrotg) (double *, double *, double *, double *); +int BLASFUNC(crotg) (float *, float *, float *, float *); +int BLASFUNC(zrotg) (double *, double *, double *, double *); +int BLASFUNC(xrotg) (double *, double *, double *, double *); + +int BLASFUNC(srotmg)(float *, float *, float *, float *, float *); +int BLASFUNC(drotmg)(double *, double *, double *, double *, double *); + +int BLASFUNC(srotm) (int *, float *, int *, float *, int *, float *); +int BLASFUNC(drotm) (int *, double *, int *, double *, int *, double *); +int BLASFUNC(qrotm) (int *, double *, int *, double *, int *, double *); + +/* Level 2 routines */ + +int BLASFUNC(sger)(int *, int *, float *, float *, int *, + float *, int *, float *, int *); +int BLASFUNC(dger)(int *, int *, double *, double *, int *, + double *, int *, double *, int *); +int BLASFUNC(qger)(int *, int *, double *, double *, int *, + double *, int *, double *, int *); +int BLASFUNC(cgeru)(int *, int *, float *, float *, int *, + float *, int *, float *, int *); +int BLASFUNC(cgerc)(int *, int *, float *, float *, int *, + float *, int *, float *, int *); +int BLASFUNC(zgeru)(int *, int *, double *, double *, int *, + double *, int *, double *, int *); +int BLASFUNC(zgerc)(int *, int *, double *, double *, int *, + double *, int *, double *, int *); +int BLASFUNC(xgeru)(int *, int *, double *, double *, int *, + double *, int *, double *, int *); +int BLASFUNC(xgerc)(int *, int *, double *, double *, int *, + double *, int *, double *, int *); + +int BLASFUNC(sgemv)(char *, int *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(dgemv)(char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(qgemv)(char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(cgemv)(char *, int *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(zgemv)(char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(xgemv)(char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); + +int BLASFUNC(strsv) (char *, char *, char *, int *, float *, int *, + float *, int *); +int BLASFUNC(dtrsv) (char *, char *, char *, int *, double *, int *, + double *, int *); +int BLASFUNC(qtrsv) (char *, char *, char *, int *, double *, int *, + double *, int *); +int BLASFUNC(ctrsv) (char *, char *, char *, int *, float *, int *, + float *, int *); +int BLASFUNC(ztrsv) (char *, char *, char *, int *, double *, int *, + double *, int *); +int BLASFUNC(xtrsv) (char *, char *, char *, int *, double *, int *, + double *, int *); + +int BLASFUNC(stpsv) (char *, char *, char *, int *, float *, float *, int *); +int BLASFUNC(dtpsv) (char *, char *, char *, int *, double *, double *, int *); +int BLASFUNC(qtpsv) (char *, char *, char *, int *, double *, double *, int *); +int BLASFUNC(ctpsv) (char *, char *, char *, int *, float *, float *, int *); +int BLASFUNC(ztpsv) (char *, char *, char *, int *, double *, double *, int *); +int BLASFUNC(xtpsv) (char *, char *, char *, int *, double *, double *, int *); + +int BLASFUNC(strmv) (char *, char *, char *, int *, float *, int *, + float *, int *); +int BLASFUNC(dtrmv) (char *, char *, char *, int *, double *, int *, + double *, int *); +int BLASFUNC(qtrmv) (char *, char *, char *, int *, double *, int *, + double *, int *); +int BLASFUNC(ctrmv) (char *, char *, char *, int *, float *, int *, + float *, int *); +int BLASFUNC(ztrmv) (char *, char *, char *, int *, double *, int *, + double *, int *); +int BLASFUNC(xtrmv) (char *, char *, char *, int *, double *, int *, + double *, int *); + +int BLASFUNC(stpmv) (char *, char *, char *, int *, float *, float *, int *); +int BLASFUNC(dtpmv) (char *, char *, char *, int *, double *, double *, int *); +int BLASFUNC(qtpmv) (char *, char *, char *, int *, double *, double *, int *); +int BLASFUNC(ctpmv) (char *, char *, char *, int *, float *, float *, int *); +int BLASFUNC(ztpmv) (char *, char *, char *, int *, double *, double *, int *); +int BLASFUNC(xtpmv) (char *, char *, char *, int *, double *, double *, int *); + +int BLASFUNC(stbmv) (char *, char *, char *, int *, int *, float *, int *, float *, int *); +int BLASFUNC(dtbmv) (char *, char *, char *, int *, int *, double *, int *, double *, int *); +int BLASFUNC(qtbmv) (char *, char *, char *, int *, int *, double *, int *, double *, int *); +int BLASFUNC(ctbmv) (char *, char *, char *, int *, int *, float *, int *, float *, int *); +int BLASFUNC(ztbmv) (char *, char *, char *, int *, int *, double *, int *, double *, int *); +int BLASFUNC(xtbmv) (char *, char *, char *, int *, int *, double *, int *, double *, int *); + +int BLASFUNC(stbsv) (char *, char *, char *, int *, int *, float *, int *, float *, int *); +int BLASFUNC(dtbsv) (char *, char *, char *, int *, int *, double *, int *, double *, int *); +int BLASFUNC(qtbsv) (char *, char *, char *, int *, int *, double *, int *, double *, int *); +int BLASFUNC(ctbsv) (char *, char *, char *, int *, int *, float *, int *, float *, int *); +int BLASFUNC(ztbsv) (char *, char *, char *, int *, int *, double *, int *, double *, int *); +int BLASFUNC(xtbsv) (char *, char *, char *, int *, int *, double *, int *, double *, int *); + +int BLASFUNC(ssymv) (char *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(dsymv) (char *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(qsymv) (char *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(csymv) (char *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(zsymv) (char *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(xsymv) (char *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); + +int BLASFUNC(sspmv) (char *, int *, float *, float *, + float *, int *, float *, float *, int *); +int BLASFUNC(dspmv) (char *, int *, double *, double *, + double *, int *, double *, double *, int *); +int BLASFUNC(qspmv) (char *, int *, double *, double *, + double *, int *, double *, double *, int *); +int BLASFUNC(cspmv) (char *, int *, float *, float *, + float *, int *, float *, float *, int *); +int BLASFUNC(zspmv) (char *, int *, double *, double *, + double *, int *, double *, double *, int *); +int BLASFUNC(xspmv) (char *, int *, double *, double *, + double *, int *, double *, double *, int *); + +int BLASFUNC(ssyr) (char *, int *, float *, float *, int *, + float *, int *); +int BLASFUNC(dsyr) (char *, int *, double *, double *, int *, + double *, int *); +int BLASFUNC(qsyr) (char *, int *, double *, double *, int *, + double *, int *); +int BLASFUNC(csyr) (char *, int *, float *, float *, int *, + float *, int *); +int BLASFUNC(zsyr) (char *, int *, double *, double *, int *, + double *, int *); +int BLASFUNC(xsyr) (char *, int *, double *, double *, int *, + double *, int *); + +int BLASFUNC(ssyr2) (char *, int *, float *, + float *, int *, float *, int *, float *, int *); +int BLASFUNC(dsyr2) (char *, int *, double *, + double *, int *, double *, int *, double *, int *); +int BLASFUNC(qsyr2) (char *, int *, double *, + double *, int *, double *, int *, double *, int *); +int BLASFUNC(csyr2) (char *, int *, float *, + float *, int *, float *, int *, float *, int *); +int BLASFUNC(zsyr2) (char *, int *, double *, + double *, int *, double *, int *, double *, int *); +int BLASFUNC(xsyr2) (char *, int *, double *, + double *, int *, double *, int *, double *, int *); + +int BLASFUNC(sspr) (char *, int *, float *, float *, int *, + float *); +int BLASFUNC(dspr) (char *, int *, double *, double *, int *, + double *); +int BLASFUNC(qspr) (char *, int *, double *, double *, int *, + double *); +int BLASFUNC(cspr) (char *, int *, float *, float *, int *, + float *); +int BLASFUNC(zspr) (char *, int *, double *, double *, int *, + double *); +int BLASFUNC(xspr) (char *, int *, double *, double *, int *, + double *); + +int BLASFUNC(sspr2) (char *, int *, float *, + float *, int *, float *, int *, float *); +int BLASFUNC(dspr2) (char *, int *, double *, + double *, int *, double *, int *, double *); +int BLASFUNC(qspr2) (char *, int *, double *, + double *, int *, double *, int *, double *); +int BLASFUNC(cspr2) (char *, int *, float *, + float *, int *, float *, int *, float *); +int BLASFUNC(zspr2) (char *, int *, double *, + double *, int *, double *, int *, double *); +int BLASFUNC(xspr2) (char *, int *, double *, + double *, int *, double *, int *, double *); + +int BLASFUNC(cher) (char *, int *, float *, float *, int *, + float *, int *); +int BLASFUNC(zher) (char *, int *, double *, double *, int *, + double *, int *); +int BLASFUNC(xher) (char *, int *, double *, double *, int *, + double *, int *); + +int BLASFUNC(chpr) (char *, int *, float *, float *, int *, float *); +int BLASFUNC(zhpr) (char *, int *, double *, double *, int *, double *); +int BLASFUNC(xhpr) (char *, int *, double *, double *, int *, double *); + +int BLASFUNC(cher2) (char *, int *, float *, + float *, int *, float *, int *, float *, int *); +int BLASFUNC(zher2) (char *, int *, double *, + double *, int *, double *, int *, double *, int *); +int BLASFUNC(xher2) (char *, int *, double *, + double *, int *, double *, int *, double *, int *); + +int BLASFUNC(chpr2) (char *, int *, float *, + float *, int *, float *, int *, float *); +int BLASFUNC(zhpr2) (char *, int *, double *, + double *, int *, double *, int *, double *); +int BLASFUNC(xhpr2) (char *, int *, double *, + double *, int *, double *, int *, double *); + +int BLASFUNC(chemv) (char *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(zhemv) (char *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(xhemv) (char *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); + +int BLASFUNC(chpmv) (char *, int *, float *, float *, + float *, int *, float *, float *, int *); +int BLASFUNC(zhpmv) (char *, int *, double *, double *, + double *, int *, double *, double *, int *); +int BLASFUNC(xhpmv) (char *, int *, double *, double *, + double *, int *, double *, double *, int *); + +int BLASFUNC(snorm)(char *, int *, int *, float *, int *); +int BLASFUNC(dnorm)(char *, int *, int *, double *, int *); +int BLASFUNC(cnorm)(char *, int *, int *, float *, int *); +int BLASFUNC(znorm)(char *, int *, int *, double *, int *); + +int BLASFUNC(sgbmv)(char *, int *, int *, int *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(dgbmv)(char *, int *, int *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(qgbmv)(char *, int *, int *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(cgbmv)(char *, int *, int *, int *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(zgbmv)(char *, int *, int *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(xgbmv)(char *, int *, int *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); + +int BLASFUNC(ssbmv)(char *, int *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(dsbmv)(char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(qsbmv)(char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(csbmv)(char *, int *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(zsbmv)(char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(xsbmv)(char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); + +int BLASFUNC(chbmv)(char *, int *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(zhbmv)(char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(xhbmv)(char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); + +/* Level 3 routines */ + +int BLASFUNC(sgemm)(char *, char *, int *, int *, int *, float *, + float *, int *, float *, int *, float *, float *, int *); +int BLASFUNC(dgemm)(char *, char *, int *, int *, int *, double *, + double *, int *, double *, int *, double *, double *, int *); +int BLASFUNC(qgemm)(char *, char *, int *, int *, int *, double *, + double *, int *, double *, int *, double *, double *, int *); +int BLASFUNC(cgemm)(char *, char *, int *, int *, int *, float *, + float *, int *, float *, int *, float *, float *, int *); +int BLASFUNC(zgemm)(char *, char *, int *, int *, int *, double *, + double *, int *, double *, int *, double *, double *, int *); +int BLASFUNC(xgemm)(char *, char *, int *, int *, int *, double *, + double *, int *, double *, int *, double *, double *, int *); + +int BLASFUNC(cgemm3m)(char *, char *, int *, int *, int *, float *, + float *, int *, float *, int *, float *, float *, int *); +int BLASFUNC(zgemm3m)(char *, char *, int *, int *, int *, double *, + double *, int *, double *, int *, double *, double *, int *); +int BLASFUNC(xgemm3m)(char *, char *, int *, int *, int *, double *, + double *, int *, double *, int *, double *, double *, int *); + +int BLASFUNC(sge2mm)(char *, char *, char *, int *, int *, + float *, float *, int *, float *, int *, + float *, float *, int *); +int BLASFUNC(dge2mm)(char *, char *, char *, int *, int *, + double *, double *, int *, double *, int *, + double *, double *, int *); +int BLASFUNC(cge2mm)(char *, char *, char *, int *, int *, + float *, float *, int *, float *, int *, + float *, float *, int *); +int BLASFUNC(zge2mm)(char *, char *, char *, int *, int *, + double *, double *, int *, double *, int *, + double *, double *, int *); + +int BLASFUNC(strsm)(char *, char *, char *, char *, int *, int *, + float *, float *, int *, float *, int *); +int BLASFUNC(dtrsm)(char *, char *, char *, char *, int *, int *, + double *, double *, int *, double *, int *); +int BLASFUNC(qtrsm)(char *, char *, char *, char *, int *, int *, + double *, double *, int *, double *, int *); +int BLASFUNC(ctrsm)(char *, char *, char *, char *, int *, int *, + float *, float *, int *, float *, int *); +int BLASFUNC(ztrsm)(char *, char *, char *, char *, int *, int *, + double *, double *, int *, double *, int *); +int BLASFUNC(xtrsm)(char *, char *, char *, char *, int *, int *, + double *, double *, int *, double *, int *); + +int BLASFUNC(strmm)(char *, char *, char *, char *, int *, int *, + float *, float *, int *, float *, int *); +int BLASFUNC(dtrmm)(char *, char *, char *, char *, int *, int *, + double *, double *, int *, double *, int *); +int BLASFUNC(qtrmm)(char *, char *, char *, char *, int *, int *, + double *, double *, int *, double *, int *); +int BLASFUNC(ctrmm)(char *, char *, char *, char *, int *, int *, + float *, float *, int *, float *, int *); +int BLASFUNC(ztrmm)(char *, char *, char *, char *, int *, int *, + double *, double *, int *, double *, int *); +int BLASFUNC(xtrmm)(char *, char *, char *, char *, int *, int *, + double *, double *, int *, double *, int *); + +int BLASFUNC(ssymm)(char *, char *, int *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(dsymm)(char *, char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(qsymm)(char *, char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(csymm)(char *, char *, int *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(zsymm)(char *, char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(xsymm)(char *, char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); + +int BLASFUNC(csymm3m)(char *, char *, int *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(zsymm3m)(char *, char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(xsymm3m)(char *, char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); + +int BLASFUNC(ssyrk)(char *, char *, int *, int *, float *, float *, int *, + float *, float *, int *); +int BLASFUNC(dsyrk)(char *, char *, int *, int *, double *, double *, int *, + double *, double *, int *); +int BLASFUNC(qsyrk)(char *, char *, int *, int *, double *, double *, int *, + double *, double *, int *); +int BLASFUNC(csyrk)(char *, char *, int *, int *, float *, float *, int *, + float *, float *, int *); +int BLASFUNC(zsyrk)(char *, char *, int *, int *, double *, double *, int *, + double *, double *, int *); +int BLASFUNC(xsyrk)(char *, char *, int *, int *, double *, double *, int *, + double *, double *, int *); + +int BLASFUNC(ssyr2k)(char *, char *, int *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(dsyr2k)(char *, char *, int *, int *, double *, double *, int *, + double*, int *, double *, double *, int *); +int BLASFUNC(qsyr2k)(char *, char *, int *, int *, double *, double *, int *, + double*, int *, double *, double *, int *); +int BLASFUNC(csyr2k)(char *, char *, int *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(zsyr2k)(char *, char *, int *, int *, double *, double *, int *, + double*, int *, double *, double *, int *); +int BLASFUNC(xsyr2k)(char *, char *, int *, int *, double *, double *, int *, + double*, int *, double *, double *, int *); + +int BLASFUNC(chemm)(char *, char *, int *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(zhemm)(char *, char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(xhemm)(char *, char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); + +int BLASFUNC(chemm3m)(char *, char *, int *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(zhemm3m)(char *, char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); +int BLASFUNC(xhemm3m)(char *, char *, int *, int *, double *, double *, int *, + double *, int *, double *, double *, int *); + +int BLASFUNC(cherk)(char *, char *, int *, int *, float *, float *, int *, + float *, float *, int *); +int BLASFUNC(zherk)(char *, char *, int *, int *, double *, double *, int *, + double *, double *, int *); +int BLASFUNC(xherk)(char *, char *, int *, int *, double *, double *, int *, + double *, double *, int *); + +int BLASFUNC(cher2k)(char *, char *, int *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(zher2k)(char *, char *, int *, int *, double *, double *, int *, + double*, int *, double *, double *, int *); +int BLASFUNC(xher2k)(char *, char *, int *, int *, double *, double *, int *, + double*, int *, double *, double *, int *); +int BLASFUNC(cher2m)(char *, char *, char *, int *, int *, float *, float *, int *, + float *, int *, float *, float *, int *); +int BLASFUNC(zher2m)(char *, char *, char *, int *, int *, double *, double *, int *, + double*, int *, double *, double *, int *); +int BLASFUNC(xher2m)(char *, char *, char *, int *, int *, double *, double *, int *, + double*, int *, double *, double *, int *); + +int BLASFUNC(sgemt)(char *, int *, int *, float *, float *, int *, + float *, int *); +int BLASFUNC(dgemt)(char *, int *, int *, double *, double *, int *, + double *, int *); +int BLASFUNC(cgemt)(char *, int *, int *, float *, float *, int *, + float *, int *); +int BLASFUNC(zgemt)(char *, int *, int *, double *, double *, int *, + double *, int *); + +int BLASFUNC(sgema)(char *, char *, int *, int *, float *, + float *, int *, float *, float *, int *, float *, int *); +int BLASFUNC(dgema)(char *, char *, int *, int *, double *, + double *, int *, double*, double *, int *, double*, int *); +int BLASFUNC(cgema)(char *, char *, int *, int *, float *, + float *, int *, float *, float *, int *, float *, int *); +int BLASFUNC(zgema)(char *, char *, int *, int *, double *, + double *, int *, double*, double *, int *, double*, int *); + +int BLASFUNC(sgems)(char *, char *, int *, int *, float *, + float *, int *, float *, float *, int *, float *, int *); +int BLASFUNC(dgems)(char *, char *, int *, int *, double *, + double *, int *, double*, double *, int *, double*, int *); +int BLASFUNC(cgems)(char *, char *, int *, int *, float *, + float *, int *, float *, float *, int *, float *, int *); +int BLASFUNC(zgems)(char *, char *, int *, int *, double *, + double *, int *, double*, double *, int *, double*, int *); + +int BLASFUNC(sgetf2)(int *, int *, float *, int *, int *, int *); +int BLASFUNC(dgetf2)(int *, int *, double *, int *, int *, int *); +int BLASFUNC(qgetf2)(int *, int *, double *, int *, int *, int *); +int BLASFUNC(cgetf2)(int *, int *, float *, int *, int *, int *); +int BLASFUNC(zgetf2)(int *, int *, double *, int *, int *, int *); +int BLASFUNC(xgetf2)(int *, int *, double *, int *, int *, int *); + +int BLASFUNC(sgetrf)(int *, int *, float *, int *, int *, int *); +int BLASFUNC(dgetrf)(int *, int *, double *, int *, int *, int *); +int BLASFUNC(qgetrf)(int *, int *, double *, int *, int *, int *); +int BLASFUNC(cgetrf)(int *, int *, float *, int *, int *, int *); +int BLASFUNC(zgetrf)(int *, int *, double *, int *, int *, int *); +int BLASFUNC(xgetrf)(int *, int *, double *, int *, int *, int *); + +int BLASFUNC(slaswp)(int *, float *, int *, int *, int *, int *, int *); +int BLASFUNC(dlaswp)(int *, double *, int *, int *, int *, int *, int *); +int BLASFUNC(qlaswp)(int *, double *, int *, int *, int *, int *, int *); +int BLASFUNC(claswp)(int *, float *, int *, int *, int *, int *, int *); +int BLASFUNC(zlaswp)(int *, double *, int *, int *, int *, int *, int *); +int BLASFUNC(xlaswp)(int *, double *, int *, int *, int *, int *, int *); + +int BLASFUNC(sgetrs)(char *, int *, int *, float *, int *, int *, float *, int *, int *); +int BLASFUNC(dgetrs)(char *, int *, int *, double *, int *, int *, double *, int *, int *); +int BLASFUNC(qgetrs)(char *, int *, int *, double *, int *, int *, double *, int *, int *); +int BLASFUNC(cgetrs)(char *, int *, int *, float *, int *, int *, float *, int *, int *); +int BLASFUNC(zgetrs)(char *, int *, int *, double *, int *, int *, double *, int *, int *); +int BLASFUNC(xgetrs)(char *, int *, int *, double *, int *, int *, double *, int *, int *); + +int BLASFUNC(sgesv)(int *, int *, float *, int *, int *, float *, int *, int *); +int BLASFUNC(dgesv)(int *, int *, double *, int *, int *, double*, int *, int *); +int BLASFUNC(qgesv)(int *, int *, double *, int *, int *, double*, int *, int *); +int BLASFUNC(cgesv)(int *, int *, float *, int *, int *, float *, int *, int *); +int BLASFUNC(zgesv)(int *, int *, double *, int *, int *, double*, int *, int *); +int BLASFUNC(xgesv)(int *, int *, double *, int *, int *, double*, int *, int *); + +int BLASFUNC(spotf2)(char *, int *, float *, int *, int *); +int BLASFUNC(dpotf2)(char *, int *, double *, int *, int *); +int BLASFUNC(qpotf2)(char *, int *, double *, int *, int *); +int BLASFUNC(cpotf2)(char *, int *, float *, int *, int *); +int BLASFUNC(zpotf2)(char *, int *, double *, int *, int *); +int BLASFUNC(xpotf2)(char *, int *, double *, int *, int *); + +int BLASFUNC(spotrf)(char *, int *, float *, int *, int *); +int BLASFUNC(dpotrf)(char *, int *, double *, int *, int *); +int BLASFUNC(qpotrf)(char *, int *, double *, int *, int *); +int BLASFUNC(cpotrf)(char *, int *, float *, int *, int *); +int BLASFUNC(zpotrf)(char *, int *, double *, int *, int *); +int BLASFUNC(xpotrf)(char *, int *, double *, int *, int *); + +int BLASFUNC(slauu2)(char *, int *, float *, int *, int *); +int BLASFUNC(dlauu2)(char *, int *, double *, int *, int *); +int BLASFUNC(qlauu2)(char *, int *, double *, int *, int *); +int BLASFUNC(clauu2)(char *, int *, float *, int *, int *); +int BLASFUNC(zlauu2)(char *, int *, double *, int *, int *); +int BLASFUNC(xlauu2)(char *, int *, double *, int *, int *); + +int BLASFUNC(slauum)(char *, int *, float *, int *, int *); +int BLASFUNC(dlauum)(char *, int *, double *, int *, int *); +int BLASFUNC(qlauum)(char *, int *, double *, int *, int *); +int BLASFUNC(clauum)(char *, int *, float *, int *, int *); +int BLASFUNC(zlauum)(char *, int *, double *, int *, int *); +int BLASFUNC(xlauum)(char *, int *, double *, int *, int *); + +int BLASFUNC(strti2)(char *, char *, int *, float *, int *, int *); +int BLASFUNC(dtrti2)(char *, char *, int *, double *, int *, int *); +int BLASFUNC(qtrti2)(char *, char *, int *, double *, int *, int *); +int BLASFUNC(ctrti2)(char *, char *, int *, float *, int *, int *); +int BLASFUNC(ztrti2)(char *, char *, int *, double *, int *, int *); +int BLASFUNC(xtrti2)(char *, char *, int *, double *, int *, int *); + +int BLASFUNC(strtri)(char *, char *, int *, float *, int *, int *); +int BLASFUNC(dtrtri)(char *, char *, int *, double *, int *, int *); +int BLASFUNC(qtrtri)(char *, char *, int *, double *, int *, int *); +int BLASFUNC(ctrtri)(char *, char *, int *, float *, int *, int *); +int BLASFUNC(ztrtri)(char *, char *, int *, double *, int *, int *); +int BLASFUNC(xtrtri)(char *, char *, int *, double *, int *, int *); + +int BLASFUNC(spotri)(char *, int *, float *, int *, int *); +int BLASFUNC(dpotri)(char *, int *, double *, int *, int *); +int BLASFUNC(qpotri)(char *, int *, double *, int *, int *); +int BLASFUNC(cpotri)(char *, int *, float *, int *, int *); +int BLASFUNC(zpotri)(char *, int *, double *, int *, int *); +int BLASFUNC(xpotri)(char *, int *, double *, int *, int *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extern/Eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h b/extern/Eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h index 7d509e78f3a..5b979ebf89d 100644 --- a/extern/Eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h +++ b/extern/Eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h @@ -29,6 +29,16 @@ operator/(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const */ EIGEN_MAKE_CWISE_BINARY_OP(min,internal::scalar_min_op) +/** \returns an expression of the coefficient-wise min of \c *this and scalar \a other + * + * \sa max() + */ +EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const ConstantReturnType> +(min)(const Scalar &other) const +{ + return (min)(Derived::PlainObject::Constant(rows(), cols(), other)); +} + /** \returns an expression of the coefficient-wise max of \c *this and \a other * * Example: \include Cwise_max.cpp @@ -38,6 +48,16 @@ EIGEN_MAKE_CWISE_BINARY_OP(min,internal::scalar_min_op) */ EIGEN_MAKE_CWISE_BINARY_OP(max,internal::scalar_max_op) +/** \returns an expression of the coefficient-wise max of \c *this and scalar \a other + * + * \sa min() + */ +EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const ConstantReturnType> +(max)(const Scalar &other) const +{ + return (max)(Derived::PlainObject::Constant(rows(), cols(), other)); +} + /** \returns an expression of the coefficient-wise \< operator of *this and \a other * * Example: \include Cwise_less.cpp @@ -141,3 +161,39 @@ operator-(const Scalar& scalar,const EIGEN_CURRENT_STORAGE_BASE_CLASS& { return (-other) + scalar; } + +/** \returns an expression of the coefficient-wise && operator of *this and \a other + * + * \warning this operator is for expression of bool only. + * + * Example: \include Cwise_boolean_and.cpp + * Output: \verbinclude Cwise_boolean_and.out + * + * \sa operator||(), select() + */ +template +inline const CwiseBinaryOp +operator&&(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const +{ + EIGEN_STATIC_ASSERT((internal::is_same::value && internal::is_same::value), + THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL); + return CwiseBinaryOp(derived(),other.derived()); +} + +/** \returns an expression of the coefficient-wise || operator of *this and \a other + * + * \warning this operator is for expression of bool only. + * + * Example: \include Cwise_boolean_or.cpp + * Output: \verbinclude Cwise_boolean_or.out + * + * \sa operator&&(), select() + */ +template +inline const CwiseBinaryOp +operator||(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const +{ + EIGEN_STATIC_ASSERT((internal::is_same::value && internal::is_same::value), + THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL); + return CwiseBinaryOp(derived(),other.derived()); +} diff --git a/extern/Eigen3/Eigen/src/plugins/BlockMethods.h b/extern/Eigen3/Eigen/src/plugins/BlockMethods.h index 4eba933388a..ef224001a54 100644 --- a/extern/Eigen3/Eigen/src/plugins/BlockMethods.h +++ b/extern/Eigen3/Eigen/src/plugins/BlockMethods.h @@ -4,24 +4,9 @@ // Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2006-2010 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_BLOCKMETHODS_H #define EIGEN_BLOCKMETHODS_H diff --git a/extern/Eigen3/Eigen/src/plugins/CommonCwiseBinaryOps.h b/extern/Eigen3/Eigen/src/plugins/CommonCwiseBinaryOps.h index 8f7765e72bd..688d2244088 100644 --- a/extern/Eigen3/Eigen/src/plugins/CommonCwiseBinaryOps.h +++ b/extern/Eigen3/Eigen/src/plugins/CommonCwiseBinaryOps.h @@ -4,24 +4,9 @@ // Copyright (C) 2008-2009 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // This file is a base class plugin containing common coefficient wise functions. diff --git a/extern/Eigen3/Eigen/src/plugins/CommonCwiseUnaryOps.h b/extern/Eigen3/Eigen/src/plugins/CommonCwiseUnaryOps.h index 941d5153c59..08e931aaddd 100644 --- a/extern/Eigen3/Eigen/src/plugins/CommonCwiseUnaryOps.h +++ b/extern/Eigen3/Eigen/src/plugins/CommonCwiseUnaryOps.h @@ -4,24 +4,9 @@ // Copyright (C) 2008-2009 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // This file is a base class plugin containing common coefficient wise functions. diff --git a/extern/Eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h b/extern/Eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h index 35183f91f80..3a737df7b86 100644 --- a/extern/Eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h +++ b/extern/Eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h @@ -4,24 +4,9 @@ // Copyright (C) 2008-2009 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // This file is a base class plugin containing matrix specifics coefficient wise functions. @@ -91,6 +76,16 @@ cwiseMin(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); } +/** \returns an expression of the coefficient-wise min of *this and scalar \a other + * + * \sa class CwiseBinaryOp, min() + */ +EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const ConstantReturnType> +cwiseMin(const Scalar &other) const +{ + return cwiseMin(Derived::PlainObject::Constant(rows(), cols(), other)); +} + /** \returns an expression of the coefficient-wise max of *this and \a other * * Example: \include MatrixBase_cwiseMax.cpp @@ -105,6 +100,17 @@ cwiseMax(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); } +/** \returns an expression of the coefficient-wise max of *this and scalar \a other + * + * \sa class CwiseBinaryOp, min() + */ +EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const ConstantReturnType> +cwiseMax(const Scalar &other) const +{ + return cwiseMax(Derived::PlainObject::Constant(rows(), cols(), other)); +} + + /** \returns an expression of the coefficient-wise quotient of *this and \a other * * Example: \include MatrixBase_cwiseQuotient.cpp diff --git a/extern/Eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h b/extern/Eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h index a3d9a0e1465..0cf0640bae6 100644 --- a/extern/Eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h +++ b/extern/Eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h @@ -4,24 +4,9 @@ // Copyright (C) 2008-2009 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // This file is a base class plugin containing matrix specifics coefficient wise functions. diff --git a/extern/bullet2/patches/convex_hull.patch b/extern/bullet2/patches/convex_hull.patch new file mode 100644 index 00000000000..1b2978221fb --- /dev/null +++ b/extern/bullet2/patches/convex_hull.patch @@ -0,0 +1,127 @@ +Index: extern/bullet2/src/Bullet-C-Api.h +=================================================================== +--- extern/bullet2/src/Bullet-C-Api.h (revision 51556) ++++ extern/bullet2/src/Bullet-C-Api.h (working copy) +@@ -167,6 +167,16 @@ extern "C" { + // needed for source/blender/blenkernel/intern/collision.c + double plNearestPoints(float p1[3], float p2[3], float p3[3], float q1[3], float q2[3], float q3[3], float *pa, float *pb, float normal[3]); + ++ ++ /* Convex Hull */ ++ PL_DECLARE_HANDLE(plConvexHull); ++ plConvexHull plConvexHullCompute(float (*coords)[3], int count); ++ int plConvexHullNumVertices(plConvexHull hull); ++ int plConvexHullNumFaces(plConvexHull hull); ++ void plConvexHullGetVertex(plConvexHull hull, int n, float coords[3], int *original_index); ++ int plConvexHullGetFaceSize(plConvexHull hull, int n); ++ void plConvexHullGetFaceVertices(plConvexHull hull, int n, int *vertices); ++ + #ifdef __cplusplus + } + #endif +Index: extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp +=================================================================== +--- extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp (revision 51556) ++++ extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp (working copy) +@@ -23,7 +23,7 @@ subject to the following restrictions: + #include "Bullet-C-Api.h" + #include "btBulletDynamicsCommon.h" + #include "LinearMath/btAlignedAllocator.h" +- ++#include "LinearMath/btConvexHullComputer.h" + + + #include "LinearMath/btVector3.h" +@@ -403,3 +403,60 @@ double plNearestPoints(float p1[3], float p2[3], float p3[3], float q1[3], float + return -1.0f; + } + ++// Convex hull ++plConvexHull plConvexHullCompute(float (*coords)[3], int count) ++{ ++ btConvexHullComputer *computer = new btConvexHullComputer; ++ computer->compute(reinterpret_cast< float* >(coords), ++ sizeof(*coords), count, 0, 0); ++ return reinterpret_cast(computer); ++} ++ ++int plConvexHullNumVertices(plConvexHull hull) ++{ ++ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); ++ return computer->vertices.size(); ++} ++ ++int plConvexHullNumFaces(plConvexHull hull) ++{ ++ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); ++ return computer->faces.size(); ++} ++ ++void plConvexHullGetVertex(plConvexHull hull, int n, float coords[3], ++ int *original_index) ++{ ++ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); ++ const btVector3 &v(computer->vertices[n]); ++ coords[0] = v[0]; ++ coords[1] = v[1]; ++ coords[2] = v[2]; ++ (*original_index) = computer->original_vertex_index[n]; ++} ++ ++int plConvexHullGetFaceSize(plConvexHull hull, int n) ++{ ++ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); ++ const btConvexHullComputer::Edge *e_orig, *e; ++ int count; ++ ++ for (e_orig = &computer->edges[computer->faces[n]], e = e_orig, count = 0; ++ count == 0 || e != e_orig; ++ e = e->getNextEdgeOfFace(), count++); ++ return count; ++} ++ ++void plConvexHullGetFaceVertices(plConvexHull hull, int n, int *vertices) ++{ ++ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); ++ const btConvexHullComputer::Edge *e_orig, *e; ++ int count; ++ ++ for (e_orig = &computer->edges[computer->faces[n]], e = e_orig, count = 0; ++ count == 0 || e != e_orig; ++ e = e->getNextEdgeOfFace(), count++) ++ { ++ vertices[count] = e->getTargetVertex(); ++ } ++} +Index: extern/bullet2/src/LinearMath/btConvexHullComputer.cpp +=================================================================== +--- extern/bullet2/src/LinearMath/btConvexHullComputer.cpp (revision 51556) ++++ extern/bullet2/src/LinearMath/btConvexHullComputer.cpp (working copy) +@@ -2661,6 +2661,7 @@ btScalar btConvexHullComputer::compute(const void* coords, bool doubleCoords, in + } + + vertices.resize(0); ++ original_vertex_index.resize(0); + edges.resize(0); + faces.resize(0); + +@@ -2671,6 +2672,7 @@ btScalar btConvexHullComputer::compute(const void* coords, bool doubleCoords, in + { + btConvexHullInternal::Vertex* v = oldVertices[copied]; + vertices.push_back(hull.getCoordinates(v)); ++ original_vertex_index.push_back(v->point.index); + btConvexHullInternal::Edge* firstEdge = v->edges; + if (firstEdge) + { +Index: extern/bullet2/src/LinearMath/btConvexHullComputer.h +=================================================================== +--- extern/bullet2/src/LinearMath/btConvexHullComputer.h (revision 51556) ++++ extern/bullet2/src/LinearMath/btConvexHullComputer.h (working copy) +@@ -67,6 +67,7 @@ class btConvexHullComputer + + // Vertices of the output hull + btAlignedObjectArray vertices; ++ btAlignedObjectArray original_vertex_index; + + // Edges of the output hull + btAlignedObjectArray edges; diff --git a/extern/bullet2/readme.txt b/extern/bullet2/readme.txt index 343cb104c4d..7f5a7f1e163 100644 --- a/extern/bullet2/readme.txt +++ b/extern/bullet2/readme.txt @@ -14,6 +14,8 @@ Apply patches/make_id.patch to prevent duplicated define of MAKE_ID macro in ble side and bullet side. Sergey -Apply patches/ghost_character.path to prevent characters from colliding with ghost objects. +Apply patches/ghost_character.patch to prevent characters from colliding with ghost objects. Mitchell +Apply patches/convex_hull.patch to add access to the convex hull +operation, used in the BMesh convex hull operator. diff --git a/extern/bullet2/src/Bullet-C-Api.h b/extern/bullet2/src/Bullet-C-Api.h index f27a17d51f7..2eabf3840e1 100644 --- a/extern/bullet2/src/Bullet-C-Api.h +++ b/extern/bullet2/src/Bullet-C-Api.h @@ -167,6 +167,16 @@ extern "C" { // needed for source/blender/blenkernel/intern/collision.c double plNearestPoints(float p1[3], float p2[3], float p3[3], float q1[3], float q2[3], float q3[3], float *pa, float *pb, float normal[3]); + + /* Convex Hull */ + PL_DECLARE_HANDLE(plConvexHull); + plConvexHull plConvexHullCompute(float (*coords)[3], int count); + int plConvexHullNumVertices(plConvexHull hull); + int plConvexHullNumFaces(plConvexHull hull); + void plConvexHullGetVertex(plConvexHull hull, int n, float coords[3], int *original_index); + int plConvexHullGetFaceSize(plConvexHull hull, int n); + void plConvexHullGetFaceVertices(plConvexHull hull, int n, int *vertices); + #ifdef __cplusplus } #endif diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp b/extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp index bd8e2748383..cf735569a9d 100644 --- a/extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp +++ b/extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp @@ -23,7 +23,7 @@ subject to the following restrictions: #include "Bullet-C-Api.h" #include "btBulletDynamicsCommon.h" #include "LinearMath/btAlignedAllocator.h" - +#include "LinearMath/btConvexHullComputer.h" #include "LinearMath/btVector3.h" @@ -403,3 +403,60 @@ double plNearestPoints(float p1[3], float p2[3], float p3[3], float q1[3], float return -1.0f; } +// Convex hull +plConvexHull plConvexHullCompute(float (*coords)[3], int count) +{ + btConvexHullComputer *computer = new btConvexHullComputer; + computer->compute(reinterpret_cast< float* >(coords), + sizeof(*coords), count, 0, 0); + return reinterpret_cast(computer); +} + +int plConvexHullNumVertices(plConvexHull hull) +{ + btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); + return computer->vertices.size(); +} + +int plConvexHullNumFaces(plConvexHull hull) +{ + btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); + return computer->faces.size(); +} + +void plConvexHullGetVertex(plConvexHull hull, int n, float coords[3], + int *original_index) +{ + btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); + const btVector3 &v(computer->vertices[n]); + coords[0] = v[0]; + coords[1] = v[1]; + coords[2] = v[2]; + (*original_index) = computer->original_vertex_index[n]; +} + +int plConvexHullGetFaceSize(plConvexHull hull, int n) +{ + btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); + const btConvexHullComputer::Edge *e_orig, *e; + int count; + + for (e_orig = &computer->edges[computer->faces[n]], e = e_orig, count = 0; + count == 0 || e != e_orig; + e = e->getNextEdgeOfFace(), count++); + return count; +} + +void plConvexHullGetFaceVertices(plConvexHull hull, int n, int *vertices) +{ + btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); + const btConvexHullComputer::Edge *e_orig, *e; + int count; + + for (e_orig = &computer->edges[computer->faces[n]], e = e_orig, count = 0; + count == 0 || e != e_orig; + e = e->getNextEdgeOfFace(), count++) + { + vertices[count] = e->getTargetVertex(); + } +} diff --git a/extern/bullet2/src/LinearMath/btConvexHullComputer.cpp b/extern/bullet2/src/LinearMath/btConvexHullComputer.cpp index c03c901c051..4fd81dac107 100644 --- a/extern/bullet2/src/LinearMath/btConvexHullComputer.cpp +++ b/extern/bullet2/src/LinearMath/btConvexHullComputer.cpp @@ -2661,6 +2661,7 @@ btScalar btConvexHullComputer::compute(const void* coords, bool doubleCoords, in } vertices.resize(0); + original_vertex_index.resize(0); edges.resize(0); faces.resize(0); @@ -2671,6 +2672,7 @@ btScalar btConvexHullComputer::compute(const void* coords, bool doubleCoords, in { btConvexHullInternal::Vertex* v = oldVertices[copied]; vertices.push_back(hull.getCoordinates(v)); + original_vertex_index.push_back(v->point.index); btConvexHullInternal::Edge* firstEdge = v->edges; if (firstEdge) { diff --git a/extern/bullet2/src/LinearMath/btConvexHullComputer.h b/extern/bullet2/src/LinearMath/btConvexHullComputer.h index 7240ac4fb52..6871ce80e00 100644 --- a/extern/bullet2/src/LinearMath/btConvexHullComputer.h +++ b/extern/bullet2/src/LinearMath/btConvexHullComputer.h @@ -67,6 +67,7 @@ class btConvexHullComputer // Vertices of the output hull btAlignedObjectArray vertices; + btAlignedObjectArray original_vertex_index; // Edges of the output hull btAlignedObjectArray edges; diff --git a/extern/carve/CMakeLists.txt b/extern/carve/CMakeLists.txt index 3916047ff32..5e917ac1e44 100644 --- a/extern/carve/CMakeLists.txt +++ b/extern/carve/CMakeLists.txt @@ -158,7 +158,7 @@ if(WITH_BOOST) -DCARVE_SYSTEM_BOOST ) - list(APPEND INC + list(APPEND INC_SYS ${BOOST_INCLUDE_DIR} ) endif() diff --git a/extern/libmv/CMakeLists.txt b/extern/libmv/CMakeLists.txt index 60cd84d89d4..38be34add75 100644 --- a/extern/libmv/CMakeLists.txt +++ b/extern/libmv/CMakeLists.txt @@ -28,31 +28,18 @@ set(INC . - ../Eigen3 - third_party/ssba - third_party/ldl/Include ../colamd/Include third_party/ceres/include ) set(INC_SYS + ../Eigen3 + third_party/ssba + third_party/ldl/Include ${PNG_INCLUDE_DIR} ${ZLIB_INCLUDE_DIRS} ) - -# XXX - FIXME -# this is a momentary hack to find unwind.h in 10.6.sdk -if(APPLE) - if(${CMAKE_OSX_DEPLOYMENT_TARGET} STREQUAL "10.6") - list(APPEND INC_SYS - ${CMAKE_OSX_SYSROOT}/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin10/4.2.1/include - ) - endif() -endif() -# XXX - END - - set(SRC libmv-capi.cpp libmv/image/array_nd.cc diff --git a/extern/libmv/bundle.sh b/extern/libmv/bundle.sh index 3f877508c46..1e386ec8096 100755 --- a/extern/libmv/bundle.sh +++ b/extern/libmv/bundle.sh @@ -124,14 +124,14 @@ cat > CMakeLists.txt << EOF set(INC . - ../Eigen3 - third_party/ssba - third_party/ldl/Include ../colamd/Include third_party/ceres/include ) set(INC_SYS + ../Eigen3 + third_party/ssba + third_party/ldl/Include \${PNG_INCLUDE_DIR} \${ZLIB_INCLUDE_DIRS} ) diff --git a/extern/libmv/libmv-capi.cpp b/extern/libmv/libmv-capi.cpp index 3d3b7398c9b..a15927f881d 100644 --- a/extern/libmv/libmv-capi.cpp +++ b/extern/libmv/libmv-capi.cpp @@ -523,7 +523,7 @@ int libmv_refineParametersAreValid(int parameters) { LIBMV_REFINE_RADIAL_DISTORTION_K1)); } -void libmv_solveRefineIntrinsics(libmv::Tracks *tracks, libmv::CameraIntrinsics *intrinsics, +static void libmv_solveRefineIntrinsics(libmv::Tracks *tracks, libmv::CameraIntrinsics *intrinsics, libmv::EuclideanReconstruction *reconstruction, int refine_intrinsics, reconstruct_progress_update_cb progress_update_callback, void *callback_customdata) { @@ -550,7 +550,8 @@ void libmv_solveRefineIntrinsics(libmv::Tracks *tracks, libmv::CameraIntrinsics } libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyframe1, int keyframe2, - int refine_intrinsics, double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, + int refine_intrinsics, double focal_length, double principal_x, double principal_y, + double k1, double k2, double k3, struct libmv_reconstructionOptions *options, reconstruct_progress_update_cb progress_update_callback, void *callback_customdata) { /* Invert the camera intrinsics. */ @@ -558,6 +559,7 @@ libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyfra libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction(); libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction; libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics; + libmv::ReconstructionOptions reconstruction_options; ReconstructUpdateCallback update_callback = ReconstructUpdateCallback(progress_update_callback, callback_customdata); @@ -566,6 +568,9 @@ libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyfra intrinsics->SetPrincipalPoint(principal_x, principal_y); intrinsics->SetRadialDistortion(k1, k2, k3); + reconstruction_options.success_threshold = options->success_threshold; + reconstruction_options.use_fallback_reconstruction = options->use_fallback_reconstruction; + for (int i = 0; i < markers.size(); ++i) { intrinsics->InvertIntrinsics(markers[i].x, markers[i].y, @@ -584,7 +589,8 @@ libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyfra libmv::EuclideanReconstructTwoFrames(keyframe_markers, reconstruction); libmv::EuclideanBundle(normalized_tracks, reconstruction); - libmv::EuclideanCompleteReconstruction(normalized_tracks, reconstruction, &update_callback); + libmv::EuclideanCompleteReconstruction(reconstruction_options, normalized_tracks, + reconstruction, &update_callback); if (refine_intrinsics) { libmv_solveRefineIntrinsics((libmv::Tracks *)tracks, intrinsics, reconstruction, @@ -1027,7 +1033,7 @@ void libmv_InvertIntrinsics(double focal_length, double principal_x, double prin /* ************ point clouds ************ */ -void libmvTransformToMat4(libmv::Mat3 &R, libmv::Vec3 &S, libmv::Vec3 &t, double M[4][4]) +static void libmvTransformToMat4(libmv::Mat3 &R, libmv::Vec3 &S, libmv::Vec3 &t, double M[4][4]) { for (int j = 0; j < 3; ++j) for (int k = 0; k < 3; ++k) diff --git a/extern/libmv/libmv-capi.h b/extern/libmv/libmv-capi.h index fc3b6f94f62..e5885e7addf 100644 --- a/extern/libmv/libmv-capi.h +++ b/extern/libmv/libmv-capi.h @@ -91,13 +91,20 @@ void libmv_tracksDestroy(struct libmv_Tracks *libmv_tracks); #define LIBMV_REFINE_RADIAL_DISTORTION_K1 (1<<2) #define LIBMV_REFINE_RADIAL_DISTORTION_K2 (1<<4) +/* TODO: make keyframes/distortion model a part of options? */ +struct libmv_reconstructionOptions { + double success_threshold; + int use_fallback_reconstruction; +}; + typedef void (*reconstruct_progress_update_cb) (void *customdata, double progress, const char *message); int libmv_refineParametersAreValid(int parameters); struct libmv_Reconstruction *libmv_solveReconstruction(struct libmv_Tracks *tracks, int keyframe1, int keyframe2, int refine_intrinsics, double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, - reconstruct_progress_update_cb progress_update_callback, void *callback_customdata); + struct libmv_reconstructionOptions *options, reconstruct_progress_update_cb progress_update_callback, + void *callback_customdata); struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *tracks, double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, reconstruct_progress_update_cb progress_update_callback, void *callback_customdata); @@ -147,14 +154,14 @@ void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmvIntr /* dsitortion */ void libmv_undistortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, - unsigned char *src, unsigned char *dst, int width, int height, int channels); + unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels); void libmv_undistortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, - float *src, float *dst, int width, int height, int channels); + float *src, float *dst, int width, int height, float overscan, int channels); void libmv_distortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, - unsigned char *src, unsigned char *dst, int width, int height, int channels); + unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels); void libmv_distortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, - float *src, float *dst, int width, int height, int channels); + float *src, float *dst, int width, int height, float overscan, int channels); /* utils */ void libmv_applyCameraIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, diff --git a/extern/libmv/libmv/multiview/euclidean_resection.cc b/extern/libmv/libmv/multiview/euclidean_resection.cc index 92862515d7e..2605bf04622 100644 --- a/extern/libmv/libmv/multiview/euclidean_resection.cc +++ b/extern/libmv/libmv/multiview/euclidean_resection.cc @@ -37,13 +37,14 @@ typedef unsigned int uint; bool EuclideanResection(const Mat2X &x_camera, const Mat3X &X_world, Mat3 *R, Vec3 *t, - ResectionMethod method) { + ResectionMethod method, + double success_threshold) { switch (method) { case RESECTION_ANSAR_DANIILIDIS: EuclideanResectionAnsarDaniilidis(x_camera, X_world, R, t); break; case RESECTION_EPNP: - return EuclideanResectionEPnP(x_camera, X_world, R, t); + return EuclideanResectionEPnP(x_camera, X_world, R, t, success_threshold); break; default: LOG(FATAL) << "Unknown resection method."; @@ -351,9 +352,9 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, } // Selects 4 virtual control points using mean and PCA. -void SelectControlPoints(const Mat3X &X_world, - Mat *X_centered, - Mat34 *X_control_points) { +static void SelectControlPoints(const Mat3X &X_world, + Mat *X_centered, + Mat34 *X_control_points) { size_t num_points = X_world.cols(); // The first virtual control point, C0, is the centroid. @@ -377,9 +378,9 @@ void SelectControlPoints(const Mat3X &X_world, } // Computes the barycentric coordinates for all real points -void ComputeBarycentricCoordinates(const Mat3X &X_world_centered, - const Mat34 &X_control_points, - Mat4X *alphas) { +static void ComputeBarycentricCoordinates(const Mat3X &X_world_centered, + const Mat34 &X_control_points, + Mat4X *alphas) { size_t num_points = X_world_centered.cols(); Mat3 C2 ; for (size_t c = 1; c < 4; c++) { @@ -398,7 +399,7 @@ void ComputeBarycentricCoordinates(const Mat3X &X_world_centered, } // Estimates the coordinates of all real points in the camera coordinate frame -void ComputePointsCoordinatesInCameraFrame( +static void ComputePointsCoordinatesInCameraFrame( const Mat4X &alphas, const Vec4 &betas, const Eigen::Matrix &U, @@ -435,8 +436,9 @@ void ComputePointsCoordinatesInCameraFrame( } bool EuclideanResectionEPnP(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t) { + const Mat3X &X_world, + Mat3 *R, Vec3 *t, + double success_threshold) { CHECK(x_camera.cols() == X_world.cols()); CHECK(x_camera.cols() > 3); size_t num_points = X_world.cols(); @@ -535,7 +537,21 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, vector ts(3); Vec rmse(3); - // TODO(julien): Document where the "1e-3" magical constant comes from below. + // At one point this threshold was 1e-3, and caused no end of problems in + // Blender by causing frames to not resect when they would have worked fine. + // When the resect failed, the projective followup is run leading to worse + // results, and often the dreaded "flipping" where objects get flipped + // between frames. Instead, disable the check for now, always succeeding. The + // ultimate check is always reprojection error anyway. + // + // TODO(keir): Decide if setting this to infinity, effectively disabling the + // check, is the right approach. So far this seems the case. + // + // TODO(sergey): Made it an option for now, in some cases it makes sense to + // still fallback to reprojection solution (see bug [#32765] from Blender bug tracker) + + // double kSuccessThreshold = std::numeric_limits::max(); + double kSuccessThreshold = success_threshold; // Find the first possible solution for R, t corresponding to: // Betas = [b00 b01 b11 b02 b12 b22 b03 b13 b23 b33] @@ -548,7 +564,7 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, Eigen::JacobiSVD svd_of_l4(l_6x4, Eigen::ComputeFullU | Eigen::ComputeFullV); Vec4 b4 = svd_of_l4.solve(rho); - if ((l_6x4 * b4).isApprox(rho, 1e-3)) { + if ((l_6x4 * b4).isApprox(rho, kSuccessThreshold)) { if (b4(0) < 0) { b4 = -b4; } @@ -574,7 +590,7 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, Vec3 b3 = svdOfL3.solve(rho); VLOG(2) << " rho = " << rho; VLOG(2) << " l_6x3 * b3 = " << l_6x3 * b3; - if ((l_6x3 * b3).isApprox(rho, 1e-3)) { + if ((l_6x3 * b3).isApprox(rho, kSuccessThreshold)) { if (b3(0) < 0) { betas(0) = std::sqrt(-b3(0)); betas(1) = (b3(2) < 0) ? std::sqrt(-b3(2)) : 0; @@ -605,7 +621,7 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, Eigen::JacobiSVD svdOfL5(l_6x5, Eigen::ComputeFullU | Eigen::ComputeFullV); Vec5 b5 = svdOfL5.solve(rho); - if ((l_6x5 * b5).isApprox(rho, 1e-3)) { + if ((l_6x5 * b5).isApprox(rho, kSuccessThreshold)) { if (b5(0) < 0) { betas(0) = std::sqrt(-b5(0)); if (b5(2) < 0) { diff --git a/extern/libmv/libmv/multiview/euclidean_resection.h b/extern/libmv/libmv/multiview/euclidean_resection.h index 08fa3d90bd3..b0428ec61fd 100644 --- a/extern/libmv/libmv/multiview/euclidean_resection.h +++ b/extern/libmv/libmv/multiview/euclidean_resection.h @@ -29,6 +29,9 @@ namespace euclidean_resection { enum ResectionMethod { RESECTION_ANSAR_DANIILIDIS, + + // The "EPnP" algorithm by Lepetit et al. + // http://cvlab.epfl.ch/~lepetit/papers/lepetit_ijcv08.pdf RESECTION_EPNP, }; @@ -42,11 +45,14 @@ enum ResectionMethod { * \param R Solution for the camera rotation matrix * \param t Solution for the camera translation vector * \param method The resection method to use. + * \param success_threshold Threshold of an error which is still considered a success + * (currently used by EPnP algorithm only) */ bool EuclideanResection(const Mat2X &x_camera, const Mat3X &X_world, Mat3 *R, Vec3 *t, - ResectionMethod method = RESECTION_EPNP); + ResectionMethod method = RESECTION_EPNP, + double success_threshold = 1e-3); /** * Computes the extrinsic parameters, R and t for a calibrated camera @@ -107,6 +113,7 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, * \param X_world 3D points in the world coordinate system * \param R Solution for the camera rotation matrix * \param t Solution for the camera translation vector + * \param success_threshold Threshold of an error which is still considered a success * * This is the algorithm described in: * "{EP$n$P: An Accurate $O(n)$ Solution to the P$n$P Problem", by V. Lepetit @@ -115,7 +122,8 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, */ bool EuclideanResectionEPnP(const Mat2X &x_camera, const Mat3X &X_world, - Mat3 *R, Vec3 *t); + Mat3 *R, Vec3 *t, + double success_threshold = 1e-3); } // namespace euclidean_resection } // namespace libmv diff --git a/extern/libmv/libmv/multiview/fundamental.cc b/extern/libmv/libmv/multiview/fundamental.cc index 7a6b4a08439..80f155e804d 100644 --- a/extern/libmv/libmv/multiview/fundamental.cc +++ b/extern/libmv/libmv/multiview/fundamental.cc @@ -28,7 +28,7 @@ namespace libmv { -void EliminateRow(const Mat34 &P, int row, Mat *X) { +static void EliminateRow(const Mat34 &P, int row, Mat *X) { X->resize(2, 4); int first_row = (row + 1) % 3; @@ -69,7 +69,7 @@ void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F) { // HZ 11.1 pag.279 (x1 = x, x2 = x') // http://www.cs.unc.edu/~marc/tutorial/node54.html -double EightPointSolver(const Mat &x1, const Mat &x2, Mat3 *F) { +static double EightPointSolver(const Mat &x1, const Mat &x2, Mat3 *F) { DCHECK_EQ(x1.rows(), 2); DCHECK_GE(x1.cols(), 8); DCHECK_EQ(x1.rows(), x2.rows()); diff --git a/extern/libmv/libmv/multiview/homography.cc b/extern/libmv/libmv/multiview/homography.cc index 366392f3923..b5c483998d8 100644 --- a/extern/libmv/libmv/multiview/homography.cc +++ b/extern/libmv/libmv/multiview/homography.cc @@ -40,7 +40,7 @@ namespace libmv { * (a-x1*g)*y1 + (b-x1*h)*y2 + c-x1 = |0| * (-x2*a+x1*d)*y1 + (-x2*b+x1*e)*y2 + -x2*c+x1*f |0| */ -bool Homography2DFromCorrespondencesLinearEuc( +static bool Homography2DFromCorrespondencesLinearEuc( const Mat &x1, const Mat &x2, Mat3 *H, diff --git a/extern/libmv/libmv/numeric/levenberg_marquardt.h b/extern/libmv/libmv/numeric/levenberg_marquardt.h index 4473b72f156..a7877e0270b 100644 --- a/extern/libmv/libmv/numeric/levenberg_marquardt.h +++ b/extern/libmv/libmv/numeric/levenberg_marquardt.h @@ -124,11 +124,11 @@ class LevenbergMarquardt { Parameters dx, x_new; int i; for (i = 0; results.status == RUNNING && i < params.max_iterations; ++i) { - VLOG(1) << "iteration: " << i; - VLOG(1) << "||f(x)||: " << f_(x).norm(); - VLOG(1) << "max(g): " << g.array().abs().maxCoeff(); - VLOG(1) << "u: " << u; - VLOG(1) << "v: " << v; + VLOG(3) << "iteration: " << i; + VLOG(3) << "||f(x)||: " << f_(x).norm(); + VLOG(3) << "max(g): " << g.array().abs().maxCoeff(); + VLOG(3) << "u: " << u; + VLOG(3) << "v: " << v; AMatrixType A_augmented = A + u*AMatrixType::Identity(J.cols(), J.cols()); Solver solver(A_augmented); diff --git a/extern/libmv/libmv/simple_pipeline/detect.cc b/extern/libmv/libmv/simple_pipeline/detect.cc index 8a093dadeca..9e3edf32d71 100644 --- a/extern/libmv/libmv/simple_pipeline/detect.cc +++ b/extern/libmv/libmv/simple_pipeline/detect.cc @@ -35,7 +35,7 @@ namespace libmv { typedef unsigned int uint; -int featurecmp(const void *a_v, const void *b_v) +static int featurecmp(const void *a_v, const void *b_v) { Feature *a = (Feature*)a_v; Feature *b = (Feature*)b_v; diff --git a/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc b/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc index 77fe2a530c4..9c06d1ef4e6 100644 --- a/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc +++ b/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc @@ -24,6 +24,7 @@ #include "libmv/multiview/projection.h" #include "libmv/numeric/levenberg_marquardt.h" #include "libmv/numeric/numeric.h" +#include "libmv/simple_pipeline/initialize_reconstruction.h" #include "libmv/simple_pipeline/reconstruction.h" #include "libmv/simple_pipeline/tracks.h" diff --git a/extern/libmv/libmv/simple_pipeline/intersect.cc b/extern/libmv/libmv/simple_pipeline/intersect.cc index b1518e04651..0c2f744dc1c 100644 --- a/extern/libmv/libmv/simple_pipeline/intersect.cc +++ b/extern/libmv/libmv/simple_pipeline/intersect.cc @@ -26,6 +26,7 @@ #include "libmv/multiview/projection.h" #include "libmv/numeric/numeric.h" #include "libmv/numeric/levenberg_marquardt.h" +#include "libmv/simple_pipeline/intersect.h" #include "libmv/simple_pipeline/reconstruction.h" #include "libmv/simple_pipeline/tracks.h" diff --git a/extern/libmv/libmv/simple_pipeline/pipeline.cc b/extern/libmv/libmv/simple_pipeline/pipeline.cc index 2459d059114..efceda5c455 100644 --- a/extern/libmv/libmv/simple_pipeline/pipeline.cc +++ b/extern/libmv/libmv/simple_pipeline/pipeline.cc @@ -50,9 +50,10 @@ struct EuclideanPipelineRoutines { EuclideanBundle(tracks, reconstruction); } - static bool Resect(const vector &markers, + static bool Resect(const ReconstructionOptions &options, + const vector &markers, EuclideanReconstruction *reconstruction, bool final_pass) { - return EuclideanResect(markers, reconstruction, final_pass); + return EuclideanResect(options, markers, reconstruction, final_pass); } static bool Intersect(const vector &markers, @@ -88,7 +89,8 @@ struct ProjectivePipelineRoutines { ProjectiveBundle(tracks, reconstruction); } - static bool Resect(const vector &markers, + static bool Resect(const ReconstructionOptions &options, + const vector &markers, ProjectiveReconstruction *reconstruction, bool final_pass) { return ProjectiveResect(markers, reconstruction); } @@ -136,6 +138,7 @@ static void CompleteReconstructionLogProress(ProgressUpdateCallback *update_call template void InternalCompleteReconstruction( + const ReconstructionOptions &options, const Tracks &tracks, typename PipelineRoutines::Reconstruction *reconstruction, ProgressUpdateCallback *update_callback = NULL) { @@ -204,7 +207,7 @@ void InternalCompleteReconstruction( if (reconstructed_markers.size() >= 5) { CompleteReconstructionLogProress(update_callback, (double)tot_resects/(max_image)); - if (PipelineRoutines::Resect(reconstructed_markers, reconstruction, false)) { + if (PipelineRoutines::Resect(options, reconstructed_markers, reconstruction, false)) { num_resects++; tot_resects++; LG << "Ran Resect() for image " << image; @@ -240,11 +243,11 @@ void InternalCompleteReconstruction( if (reconstructed_markers.size() >= 5) { CompleteReconstructionLogProress(update_callback, (double)tot_resects/(max_image)); - if (PipelineRoutines::Resect(reconstructed_markers, reconstruction, true)) { + if (PipelineRoutines::Resect(options, reconstructed_markers, reconstruction, true)) { num_resects++; - LG << "Ran Resect() for image " << image; + LG << "Ran final Resect() for image " << image; } else { - LG << "Failed Resect() for image " << image; + LG << "Failed final Resect() for image " << image; } } } @@ -325,17 +328,21 @@ double ProjectiveReprojectionError( intrinsics); } -void EuclideanCompleteReconstruction(const Tracks &tracks, +void EuclideanCompleteReconstruction(const ReconstructionOptions &options, + const Tracks &tracks, EuclideanReconstruction *reconstruction, ProgressUpdateCallback *update_callback) { - InternalCompleteReconstruction(tracks, + InternalCompleteReconstruction(options, + tracks, reconstruction, update_callback); } -void ProjectiveCompleteReconstruction(const Tracks &tracks, +void ProjectiveCompleteReconstruction(const ReconstructionOptions &options, + const Tracks &tracks, ProjectiveReconstruction *reconstruction) { - InternalCompleteReconstruction(tracks, + InternalCompleteReconstruction(options, + tracks, reconstruction); } diff --git a/extern/libmv/libmv/simple_pipeline/pipeline.h b/extern/libmv/libmv/simple_pipeline/pipeline.h index e940b57bc0d..11c11297d78 100644 --- a/extern/libmv/libmv/simple_pipeline/pipeline.h +++ b/extern/libmv/libmv/simple_pipeline/pipeline.h @@ -39,6 +39,9 @@ namespace libmv { repeated until all points and cameras are estimated. Periodically, bundle adjustment is run to ensure a quality reconstruction. + \a options are used to define some specific befaviours based on settings + see documentation for ReconstructionOptions + \a tracks should contain markers used in the reconstruction. \a reconstruction should contain at least some 3D points or some estimated cameras. The minimum number of cameras is two (with no 3D points) and the @@ -46,7 +49,8 @@ namespace libmv { \sa EuclideanResect, EuclideanIntersect, EuclideanBundle */ -void EuclideanCompleteReconstruction(const Tracks &tracks, +void EuclideanCompleteReconstruction(const ReconstructionOptions &options, + const Tracks &tracks, EuclideanReconstruction *reconstruction, ProgressUpdateCallback *update_callback = NULL); @@ -63,6 +67,9 @@ void EuclideanCompleteReconstruction(const Tracks &tracks, repeated until all points and cameras are estimated. Periodically, bundle adjustment is run to ensure a quality reconstruction. + \a options are used to define some specific befaviours based on settings + see documentation for ReconstructionOptions + \a tracks should contain markers used in the reconstruction. \a reconstruction should contain at least some 3D points or some estimated cameras. The minimum number of cameras is two (with no 3D points) and the @@ -70,7 +77,8 @@ void EuclideanCompleteReconstruction(const Tracks &tracks, \sa ProjectiveResect, ProjectiveIntersect, ProjectiveBundle */ -void ProjectiveCompleteReconstruction(const Tracks &tracks, +void ProjectiveCompleteReconstruction(const ReconstructionOptions &options, + const Tracks &tracks, ProjectiveReconstruction *reconstruction); diff --git a/extern/libmv/libmv/simple_pipeline/reconstruction.h b/extern/libmv/libmv/simple_pipeline/reconstruction.h index 947a0636476..71789e3a245 100644 --- a/extern/libmv/libmv/simple_pipeline/reconstruction.h +++ b/extern/libmv/libmv/simple_pipeline/reconstruction.h @@ -26,6 +26,17 @@ namespace libmv { +struct ReconstructionOptions { + // threshold value of reconstruction error which is still considered successful + // if reconstruction error bigger than this value, fallback reconstruction + // algorithm would be used (if enabled) + double success_threshold; + + // use fallback reconstruction algorithm in cases main reconstruction algorithm + // failed to reconstruct + bool use_fallback_reconstruction; +}; + /*! A EuclideanCamera is the location and rotation of the camera viewing \a image. diff --git a/extern/libmv/libmv/simple_pipeline/resect.cc b/extern/libmv/libmv/simple_pipeline/resect.cc index b30d959b512..4c9ca6d8677 100644 --- a/extern/libmv/libmv/simple_pipeline/resect.cc +++ b/extern/libmv/libmv/simple_pipeline/resect.cc @@ -27,6 +27,7 @@ #include "libmv/multiview/projection.h" #include "libmv/numeric/numeric.h" #include "libmv/numeric/levenberg_marquardt.h" +#include "libmv/simple_pipeline/resect.h" #include "libmv/simple_pipeline/reconstruction.h" #include "libmv/simple_pipeline/tracks.h" @@ -89,7 +90,8 @@ struct EuclideanResectCostFunction { } // namespace -bool EuclideanResect(const vector &markers, +bool EuclideanResect(const ReconstructionOptions &options, + const vector &markers, EuclideanReconstruction *reconstruction, bool final_pass) { if (markers.size() < 5) { return false; @@ -103,10 +105,25 @@ bool EuclideanResect(const vector &markers, Mat3 R; Vec3 t; - if (0 || !euclidean_resection::EuclideanResection(points_2d, points_3d, &R, &t)) { + + double success_threshold = std::numeric_limits::max(); + + if(options.use_fallback_reconstruction) + success_threshold = options.success_threshold; + + if (0 || !euclidean_resection::EuclideanResection(points_2d, points_3d, &R, &t, + euclidean_resection::RESECTION_EPNP, + success_threshold)) + { // printf("Resection for image %d failed\n", markers[0].image); LG << "Resection for image " << markers[0].image << " failed;" << " trying fallback projective resection."; + + if (!options.use_fallback_reconstruction) { + LG << "No fallback; failing resection for " << markers[0].image; + return false; + } + if (!final_pass) return false; // Euclidean resection failed. Fall back to projective resection, which is // less reliable but better conditioned when there are many points. diff --git a/extern/libmv/libmv/simple_pipeline/resect.h b/extern/libmv/libmv/simple_pipeline/resect.h index f8b5b9f68ee..1691e7ee245 100644 --- a/extern/libmv/libmv/simple_pipeline/resect.h +++ b/extern/libmv/libmv/simple_pipeline/resect.h @@ -35,6 +35,9 @@ namespace libmv { reconstruction object, and solves for the pose and orientation of the camera for that frame. + \a options are used to define some specific befaviours based on settings + see documentation for ReconstructionOptions + \a markers should contain \l Marker markers \endlink belonging to tracks visible in the one frame to be resectioned. Each of the tracks associated with the markers must have a corresponding reconstructed 3D position in the @@ -51,7 +54,8 @@ namespace libmv { \sa EuclideanIntersect, EuclideanReconstructTwoFrames */ -bool EuclideanResect(const vector &markers, +bool EuclideanResect(const ReconstructionOptions &options, + const vector &markers, EuclideanReconstruction *reconstruction, bool final_pass); /*! diff --git a/extern/libmv/libmv/tracking/track_region.cc b/extern/libmv/libmv/tracking/track_region.cc index f52919b2a61..472d58a1547 100644 --- a/extern/libmv/libmv/tracking/track_region.cc +++ b/extern/libmv/libmv/tracking/track_region.cc @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. // -// Author: mierle@google.com (Keir Mierle) +// Author: mierle@gmail.com (Keir Mierle) // // TODO(keir): While this tracking code works rather well, it has some // outragous inefficiencies. There is probably a 5-10x speedup to be had if a @@ -41,6 +41,85 @@ #include "libmv/multiview/homography.h" #include "libmv/numeric/numeric.h" +// Expand the Jet functionality of Ceres to allow mixed numeric/autodiff. +// +// TODO(keir): Push this (or something similar) into upstream Ceres. +namespace ceres { + +// A jet traits class to make it easier to work with mixed auto / numeric diff. +template +struct JetOps { + static bool IsScalar() { + return true; + } + static T GetScalar(const T& t) { + return t; + } + static void SetScalar(const T& scalar, T* t) { + *t = scalar; + } + static void ScaleDerivative(double scale_by, T *value) { + // For double, there is no derivative to scale. + } +}; + +template +struct JetOps > { + static bool IsScalar() { + return false; + } + static T GetScalar(const Jet& t) { + return t.a; + } + static void SetScalar(const T& scalar, Jet* t) { + t->a = scalar; + } + static void ScaleDerivative(double scale_by, Jet *value) { + value->v *= scale_by; + } +}; + +template +struct Chain { + static ArgumentType Rule(const FunctionType &f, + const FunctionType dfdx[kNumArgs], + const ArgumentType x[kNumArgs]) { + // In the default case of scalars, there's nothing to do since there are no + // derivatives to propagate. + return f; + } +}; + +// XXX Add documentation here! +template +struct Chain > { + static Jet Rule(const FunctionType &f, + const FunctionType dfdx[kNumArgs], + const Jet x[kNumArgs]) { + // x is itself a function of another variable ("z"); what this function + // needs to return is "f", but with the derivative with respect to z + // attached to the jet. So combine the derivative part of x's jets to form + // a Jacobian matrix between x and z (i.e. dx/dz). + Eigen::Matrix dxdz; + for (int i = 0; i < kNumArgs; ++i) { + dxdz.row(i) = x[i].v.transpose(); + } + + // Map the input gradient dfdx into an Eigen row vector. + Eigen::Map > + vector_dfdx(dfdx, 1, kNumArgs); + + // Now apply the chain rule to obtain df/dz. Combine the derivative with + // the scalar part to obtain f with full derivative information. + Jet jet_f; + jet_f.a = f; + jet_f.v = vector_dfdx.template cast() * dxdz; // Also known as dfdz. + return jet_f; + } +}; + +} // namespace ceres + namespace libmv { using ceres::Jet; @@ -57,6 +136,7 @@ TrackRegionOptions::TrackRegionOptions() sigma(0.9), num_extra_points(0), regularization_coefficient(0.0), + minimum_corner_shift_tolerance_pixels(0.005), image1_mask(NULL) { } @@ -108,45 +188,93 @@ static T SampleWithDerivative(const FloatImage &image_and_gradient, } template -class BoundaryCheckingCallback : public ceres::IterationCallback { +class TerminationCheckingCallback : public ceres::IterationCallback { public: - BoundaryCheckingCallback(const FloatImage& image2, - const Warp &warp, - const double *x1, const double *y1) - : image2_(image2), warp_(warp), x1_(x1), y1_(y1) {} + TerminationCheckingCallback(const TrackRegionOptions &options, + const FloatImage& image2, + const Warp &warp, + const double *x1, const double *y1) + : options_(options), image2_(image2), warp_(warp), x1_(x1), y1_(y1), + have_last_successful_step_(false) {} virtual ceres::CallbackReturnType operator()( const ceres::IterationSummary& summary) { + // If the step wasn't successful, there's nothing to do. + if (!summary.step_is_successful) { + return ceres::SOLVER_CONTINUE; + } // Warp the original 4 points with the current warp into image2. double x2[4]; double y2[4]; for (int i = 0; i < 4; ++i) { warp_.Forward(warp_.parameters, x1_[i], y1_[i], x2 + i, y2 + i); } - // Enusre they are all in bounds. + // Ensure the corners are all in bounds. if (!AllInBounds(image2_, x2, y2)) { + LG << "Successful step fell outside of the pattern bounds; aborting."; return ceres::SOLVER_ABORT; } + + // Ensure the minimizer is making large enough shifts to bother continuing. + // Ideally, this check would happen on the parameters themselves which + // Ceres supports directly; however, the mapping from parameter change + // magnitude to corner movement in pixels is not a simple norm. Hence, the + // need for a stateful callback which tracks the last successful set of + // parameters (and the position of the projected patch corners). + if (have_last_successful_step_) { + // Compute the maximum shift of any corner in pixels since the last + // successful iteration. + double max_change_pixels = 0; + for (int i = 0; i < 4; ++i) { + double dx = x2[i] - x2_last_successful_[i]; + double dy = y2[i] - y2_last_successful_[i]; + double change_pixels = dx*dx + dy*dy; + if (change_pixels > max_change_pixels) { + max_change_pixels = change_pixels; + } + } + max_change_pixels = sqrt(max_change_pixels); + LG << "Max patch corner shift is " << max_change_pixels; + + // Bail if the shift is too small. + if (max_change_pixels < options_.minimum_corner_shift_tolerance_pixels) { + LG << "Max patch corner shift is " << max_change_pixels + << " from the last iteration; returning success."; + return ceres::SOLVER_TERMINATE_SUCCESSFULLY; + } + } + + // Save the projected corners for checking on the next successful iteration. + for (int i = 0; i < 4; ++i) { + x2_last_successful_[i] = x2[i]; + y2_last_successful_[i] = y2[i]; + } + have_last_successful_step_ = true; return ceres::SOLVER_CONTINUE; } private: + const TrackRegionOptions &options_; const FloatImage &image2_; const Warp &warp_; const double *x1_; const double *y1_; + + bool have_last_successful_step_; + double x2_last_successful_[4]; + double y2_last_successful_[4]; }; template class PixelDifferenceCostFunctor { public: PixelDifferenceCostFunctor(const TrackRegionOptions &options, - const FloatImage &image_and_gradient1, - const FloatImage &image_and_gradient2, - const Mat3 &canonical_to_image1, - int num_samples_x, - int num_samples_y, - const Warp &warp) + const FloatImage &image_and_gradient1, + const FloatImage &image_and_gradient2, + const Mat3 &canonical_to_image1, + int num_samples_x, + int num_samples_y, + const Warp &warp) : options_(options), image_and_gradient1_(image_and_gradient1), image_and_gradient2_(image_and_gradient2), @@ -1044,6 +1172,9 @@ void CreateBrutePattern(const double *x1, const double *y1, // correlation. Instead, this is a dumb implementation. Surprisingly, it is // fast enough in practice. // +// Returns true if any alignment was found, and false if the projected pattern +// is zero sized. +// // TODO(keir): The normalization is less effective for the brute force search // than it is with the Ceres solver. It's unclear if this is a bug or due to // the original frame being too different from the reprojected reference in the @@ -1054,7 +1185,7 @@ void CreateBrutePattern(const double *x1, const double *y1, // totally different warping interface, since access to more than a the source // and current destination frame is necessary. template -void BruteTranslationOnlyInitialize(const FloatImage &image1, +bool BruteTranslationOnlyInitialize(const FloatImage &image1, const FloatImage *image1_mask, const FloatImage &image2, const int num_extra_points, @@ -1100,6 +1231,7 @@ void BruteTranslationOnlyInitialize(const FloatImage &image1, int best_c = -1; int w = pattern.cols(); int h = pattern.rows(); + for (int r = 0; r < (image2.Height() - h); ++r) { for (int c = 0; c < (image2.Width() - w); ++c) { // Compute the weighted sum of absolute differences, Eigen style. Note @@ -1124,8 +1256,12 @@ void BruteTranslationOnlyInitialize(const FloatImage &image1, } } } - CHECK_NE(best_r, -1); - CHECK_NE(best_c, -1); + + // This mean the effective pattern area is zero. This check could go earlier, + // but this is less code. + if (best_r == -1 || best_c == -1) { + return false; + } LG << "Brute force translation found a shift. " << "best_c: " << best_c << ", best_r: " << best_r << ", " @@ -1140,6 +1276,7 @@ void BruteTranslationOnlyInitialize(const FloatImage &image1, x2[i] += best_c - origin_x; y2[i] += best_r - origin_y; } + return true; } } // namespace @@ -1191,12 +1328,19 @@ void TemplatedTrackRegion(const FloatImage &image1, if (SearchAreaTooBigForDescent(image2, x2, y2) && options.use_brute_initialization) { LG << "Running brute initialization..."; - BruteTranslationOnlyInitialize(image_and_gradient1, - options.image1_mask, - image2, - options.num_extra_points, - options.use_normalized_intensities, - x1, y1, x2, y2); + bool found_any_alignment = BruteTranslationOnlyInitialize( + image_and_gradient1, + options.image1_mask, + image2, + options.num_extra_points, + options.use_normalized_intensities, + x1, y1, x2, y2); + if (!found_any_alignment) { + LG << "Brute failed to find an alignment; pattern too small. " + << "Failing entire track operation."; + result->termination = TrackRegionResult::INSUFFICIENT_PATTERN_AREA; + return; + } for (int i = 0; i < 4; ++i) { LG << "P" << i << ": (" << x1[i] << ", " << y1[i] << "); brute (" << x2[i] << ", " << y2[i] << "); (dx, dy): (" << (x2[i] - x1[i]) @@ -1260,14 +1404,15 @@ void TemplatedTrackRegion(const FloatImage &image1, // Configure the solve. ceres::Solver::Options solver_options; - solver_options.linear_solver_type = ceres::DENSE_QR; + solver_options.linear_solver_type = ceres::DENSE_NORMAL_CHOLESKY; solver_options.max_num_iterations = options.max_iterations; solver_options.update_state_every_iteration = true; solver_options.parameter_tolerance = 1e-16; solver_options.function_tolerance = 1e-16; - // Prevent the corners from going outside the destination image. - BoundaryCheckingCallback callback(image2, warp, x1, y1); + // Prevent the corners from going outside the destination image and + // terminate if the optimizer is making tiny moves (converged). + TerminationCheckingCallback callback(options, image2, warp, x1, y1); solver_options.callbacks.push_back(&callback); // Run the solve. @@ -1290,11 +1435,21 @@ void TemplatedTrackRegion(const FloatImage &image1, // TODO(keir): Update the result statistics. // TODO(keir): Add a normalize-cross-correlation variant. - CHECK_NE(summary.termination_type, ceres::USER_ABORT) << "Libmv bug."; if (summary.termination_type == ceres::USER_ABORT) { result->termination = TrackRegionResult::FELL_OUT_OF_BOUNDS; return; } + + // This happens when the minimum corner shift tolerance is reached. Due to + // how the tolerance is computed this can't be done by Ceres. So return the + // same termination enum as Ceres, even though this is slightly different + // than Ceres's parameter tolerance, which operates on the raw parameter + // values rather than the pixel shifts of the patch corners. + if (summary.termination_type == ceres::USER_SUCCESS) { + result->termination = TrackRegionResult::PARAMETER_TOLERANCE; + return; + } + #define HANDLE_TERMINATION(termination_enum) \ if (summary.termination_type == ceres::termination_enum) { \ result->termination = TrackRegionResult::termination_enum; \ @@ -1377,11 +1532,11 @@ bool SamplePlanarPatch(const FloatImage &image, image_position(0), &(*patch)(r, c, 0)); if (mask) { - float maskValue = SampleLinear(*mask, image_position(1), - image_position(0), 0); + float mask_value = SampleLinear(*mask, image_position(1), + image_position(0), 0); for (int d = 0; d < image.Depth(); d++) - (*patch)(r, c, d) *= maskValue; + (*patch)(r, c, d) *= mask_value; } } } diff --git a/extern/libmv/libmv/tracking/track_region.h b/extern/libmv/libmv/tracking/track_region.h index 22ecfc54a15..cd7ee0aa2ba 100644 --- a/extern/libmv/libmv/tracking/track_region.h +++ b/extern/libmv/libmv/tracking/track_region.h @@ -90,6 +90,11 @@ struct TrackRegionOptions { // If zero, no regularization is used. double regularization_coefficient; + // If the maximum shift of any patch corner between successful iterations of + // the solver is less than this amount, then the tracking is declared + // successful. The solver termination becomes PARAMETER_TOLERANCE. + double minimum_corner_shift_tolerance_pixels; + // If non-null, this is used as the pattern mask. It should match the size of // image1, even though only values inside the image1 quad are examined. The // values must be in the range 0.0 to 0.1. @@ -111,6 +116,7 @@ struct TrackRegionResult { DESTINATION_OUT_OF_BOUNDS, FELL_OUT_OF_BOUNDS, INSUFFICIENT_CORRELATION, + INSUFFICIENT_PATTERN_AREA, CONFIGURATION_ERROR, }; Termination termination; diff --git a/extern/libmv/third_party/ceres/CMakeLists.txt b/extern/libmv/third_party/ceres/CMakeLists.txt index e6a9e430c47..e2f06d74646 100644 --- a/extern/libmv/third_party/ceres/CMakeLists.txt +++ b/extern/libmv/third_party/ceres/CMakeLists.txt @@ -28,16 +28,17 @@ set(INC . - ../../../Eigen3 include internal ../gflags ) set(INC_SYS + ../../../Eigen3 ) set(SRC + internal/ceres/array_utils.cc internal/ceres/block_evaluate_preparer.cc internal/ceres/block_jacobian_writer.cc internal/ceres/block_jacobi_preconditioner.cc @@ -53,16 +54,19 @@ set(SRC internal/ceres/conditioned_cost_function.cc internal/ceres/conjugate_gradients_solver.cc internal/ceres/corrector.cc + internal/ceres/cxsparse.cc + internal/ceres/dense_normal_cholesky_solver.cc internal/ceres/dense_qr_solver.cc internal/ceres/dense_sparse_matrix.cc internal/ceres/detect_structure.cc + internal/ceres/dogleg_strategy.cc internal/ceres/evaluator.cc internal/ceres/file.cc internal/ceres/generated/schur_eliminator_d_d_d.cc internal/ceres/gradient_checking_cost_function.cc internal/ceres/implicit_schur_complement.cc internal/ceres/iterative_schur_complement_solver.cc - internal/ceres/levenberg_marquardt.cc + internal/ceres/levenberg_marquardt_strategy.cc internal/ceres/linear_least_squares_problems.cc internal/ceres/linear_operator.cc internal/ceres/linear_solver.cc @@ -70,6 +74,7 @@ set(SRC internal/ceres/loss_function.cc internal/ceres/normal_prior.cc internal/ceres/partitioned_matrix_view.cc + internal/ceres/polynomial_solver.cc internal/ceres/problem.cc internal/ceres/problem_impl.cc internal/ceres/program.cc @@ -88,6 +93,8 @@ set(SRC internal/ceres/stringprintf.cc internal/ceres/suitesparse.cc internal/ceres/triplet_sparse_matrix.cc + internal/ceres/trust_region_minimizer.cc + internal/ceres/trust_region_strategy.cc internal/ceres/types.cc internal/ceres/visibility_based_preconditioner.cc internal/ceres/visibility.cc @@ -96,6 +103,8 @@ set(SRC include/ceres/ceres.h include/ceres/conditioned_cost_function.h include/ceres/cost_function.h + include/ceres/crs_matrix.h + include/ceres/fpclassify.h include/ceres/internal/autodiff.h include/ceres/internal/eigen.h include/ceres/internal/fixed_array.h @@ -114,6 +123,7 @@ set(SRC include/ceres/sized_cost_function.h include/ceres/solver.h include/ceres/types.h + internal/ceres/array_utils.h internal/ceres/block_evaluate_preparer.h internal/ceres/block_jacobian_writer.h internal/ceres/block_jacobi_preconditioner.h @@ -131,10 +141,13 @@ set(SRC internal/ceres/compressed_row_sparse_matrix.h internal/ceres/conjugate_gradients_solver.h internal/ceres/corrector.h + internal/ceres/cxsparse.h internal/ceres/dense_jacobian_writer.h + internal/ceres/dense_normal_cholesky_solver.h internal/ceres/dense_qr_solver.h internal/ceres/dense_sparse_matrix.h internal/ceres/detect_structure.h + internal/ceres/dogleg_strategy.h internal/ceres/evaluator.h internal/ceres/file.h internal/ceres/gradient_checking_cost_function.h @@ -143,7 +156,7 @@ set(SRC internal/ceres/implicit_schur_complement.h internal/ceres/integral_types.h internal/ceres/iterative_schur_complement_solver.h - internal/ceres/levenberg_marquardt.h + internal/ceres/levenberg_marquardt_strategy.h internal/ceres/linear_least_squares_problems.h internal/ceres/linear_operator.h internal/ceres/linear_solver.h @@ -153,6 +166,7 @@ set(SRC internal/ceres/mutex.h internal/ceres/parameter_block.h internal/ceres/partitioned_matrix_view.h + internal/ceres/polynomial_solver.h internal/ceres/problem_impl.h internal/ceres/program_evaluator.h internal/ceres/program.h @@ -168,10 +182,13 @@ set(SRC internal/ceres/solver_impl.h internal/ceres/sparse_matrix.h internal/ceres/sparse_normal_cholesky_solver.h + internal/ceres/split.h internal/ceres/stl_util.h internal/ceres/stringprintf.h internal/ceres/suitesparse.h internal/ceres/triplet_sparse_matrix.h + internal/ceres/trust_region_minimizer.h + internal/ceres/trust_region_strategy.h internal/ceres/visibility_based_preconditioner.h internal/ceres/visibility.h ) @@ -203,7 +220,7 @@ if(WIN32) if(NOT MINGW) list(APPEND INC - third_party/msinttypes + ../msinttypes ) endif() else() @@ -214,11 +231,30 @@ endif() add_definitions( -DCERES_HAVE_PTHREAD - -D"CERES_HASH_NAMESPACE_START=namespace std { namespace tr1 {" - -D"CERES_HASH_NAMESPACE_END=}}" -DCERES_NO_SUITESPARSE - -DCERES_DONT_HAVE_PROTOCOL_BUFFERS + -DCERES_NO_CXSPARSE + -DCERES_NO_PROTOCOL_BUFFERS -DCERES_RESTRICT_SCHUR_SPECIALIZATION ) +if(MSVC10) + add_definitions( + -D"CERES_HASH_NAMESPACE_START=namespace std {" + -D"CERES_HASH_NAMESPACE_END=}" + ) +else() + add_definitions( + -D"CERES_HASH_NAMESPACE_START=namespace std { namespace tr1 {" + -D"CERES_HASH_NAMESPACE_END=}}" + ) +endif() + +if(APPLE) + if(CMAKE_OSX_DEPLOYMENT_TARGET STREQUAL "10.5") + add_definitions( + -DCERES_NO_TR1 + ) + endif() +endif() + blender_add_lib(extern_ceres "${SRC}" "${INC}" "${INC_SYS}") diff --git a/extern/libmv/third_party/ceres/ChangeLog b/extern/libmv/third_party/ceres/ChangeLog index 6e919658f13..8b84328cf98 100644 --- a/extern/libmv/third_party/ceres/ChangeLog +++ b/extern/libmv/third_party/ceres/ChangeLog @@ -1,324 +1,524 @@ -commit ca72152362ae1f4b9928c012e74b4d49d094a4ca -Merge: d297f8d 0a04199 -Author: Keir Mierle -Date: Wed May 9 13:10:59 2012 -0700 +commit 552f9f85bba89f00ca307bc18fbda1dff23bd0e4 +Author: Sameer Agarwal +Date: Fri Aug 31 07:27:22 2012 -0700 - Merge branch 'master' into windows + Various minor bug fixes to the solver logic. + + 1. CostFunction returning false is handled better. + If only the cost is being evaluated, it is possible to + use the false value as an infinite value signal/outside + a region of validity. This allows a weak form of constraint + handling. Useful for example in handling infinities. + + 2. Changed the way how the slop around zero when model_cost + is larger than the current cost. Relative instead of absolute + tolerances are used. The same logic is propagated how the + corresponding clamping of the model_cost is done. + + 3. Fixed a minor indexing bug in nist.cc. + + 4. Some minor logging fixes to nist.cc to make it more + compatible with the rest of ceres. + + Together these changes, take the successful solve count from + 41/54 to 46/54 and eliminate all NUMERICAL_FAILURE problems. + + Change-Id: If94170ea4731af5b243805c0200963dd31aa94a7 -commit 0a04199ef279cc9ea97f665fed8e7fae717813c3 -Merge: fdeb577 f2571f1 -Author: Keir Mierle -Date: Wed May 9 12:54:56 2012 -0700 +commit 0b776b5cc9634d3b88d623905b96006f7647ce3e +Author: Sameer Agarwal +Date: Thu Aug 30 15:26:17 2012 -0700 - Merge branch 'master' of https://code.google.com/p/ceres-solver + Update docs. + + Change-Id: I69d50bcd37aed3bea2190ca614f023e83172901b -commit fdeb5772cc5eeebca4d776d220d80cc91b6d0f74 -Author: Keir Mierle -Date: Wed May 9 07:38:07 2012 -0700 +commit 2d7176ad7c8fb7238ca8abd6de73415d95877494 +Author: Petter Strandmark +Date: Thu Aug 30 19:51:24 2012 -0700 - Support varying numbers of residuals in autodiff. + max_consecutive_nonmonotonic_steps should be int - This commit modifies the only function in autodiff that takes a - templated number of outputs (i.e. residuals) and makes that - template parameter a normal parameter. With that change, it - is a trivial matter to support a dynamic number of residuals. + Found via Visual Studio warning. - The API for dynamic residuals is to pass a fake number of - residuals as the second template argument to - AutoDiffCostFunction, and to pass the real number of - parameters as a second constructor argument. + Change-Id: Id2cd7de562dfc8cd35df5d5f5220dd2d7350eb2c -commit da3e0563cc12e08e7b3e0fbf11d9cc8cfe9658aa +commit 1a89bcc94e88933f89b20427a45bc40cdd23c056 Author: Sameer Agarwal -Date: Wed May 9 11:57:47 2012 -0700 +Date: Thu Aug 30 15:26:17 2012 -0700 - Typo corrections in the documentation from Bing + Better reporting on the NIST problems. + + Change-Id: I7cf774ec3242c0612dbe52fc233c3fc6cff3f031 -commit aa9526d8e8fb34c23d63e3af5bf9239b0c4ea603 +commit ea11704857a1e4a735e096896e4d775d83981499 Author: Sameer Agarwal -Date: Tue May 8 21:22:09 2012 -0700 +Date: Wed Aug 29 18:18:48 2012 -0700 - Share search paths across various library searches. - Fix typos in glog search. - Split the error messages for include and lib. - Enable building of tests by default. - Made building on homebrew installations a bit better. - Remove temporary variables for glog and gflags. + Basic harness for testing NIST problems. + + Change-Id: I5baaa24dbf0506ceedf4a9be4ed17c84974d71a1 -commit f2571f186850ed3dd316236ac4be488979df7d30 +commit 98bf14d2b95386c2c4a6c29154637943dae4c36c Author: Sameer Agarwal -Date: Wed May 9 11:57:47 2012 -0700 +Date: Thu Aug 30 10:26:44 2012 -0700 - Typo corrections in the documentation from Bing + Miscellaneous fixes. + + Change-Id: I521e11f2d20bf24960bbc6b5dab4ec8bb1503d23 -commit 8f7f11ff7d07737435428a2620c52419cf99f98e -Merge: e6c17c4 eaccbb3 -Author: Sameer Agarwal -Date: Wed May 9 11:34:15 2012 -0700 +commit 1e3cbd9a4442cdd8fda43a7fb452f19dac8c74af +Author: Petter Strandmark +Date: Wed Aug 29 09:39:56 2012 -0700 - Merge branch 'master' of https://code.google.com/p/ceres-solver + Caching the symbolic Cholesky factorization when using CXSparse + + Average factorization times for bundle adjustment test problem: + SuiteSparse: 0.2794 s. + CXSparse: 0.4039 s. + CXSparse cached: 0.2399 s. + + CXSparse will still be slower, though, because it has to compute + the transpose and J^T * J. + + Change-Id: If9cdaa3dd520bee84b56e5fd4953b56a93db6bde -commit e6c17c4c9d9307218f6f739cea39bc2d87733d4d +commit 8b64140878ccd1e183d3715c38942a81fdecefde Author: Sameer Agarwal -Date: Tue May 8 21:22:09 2012 -0700 +Date: Wed Aug 29 05:41:22 2012 -0700 - Share search paths across various library searches. - Fix typos in glog search. - Split the error messages for include and lib. - Enable building of tests by default. - Made building on homebrew installations a bit better. - Remove temporary variables for glog and gflags. + Documentation update + + Change-Id: I271a0422e7f6f42bcfd1dc6b5dc10c7a18f6a179 -commit eaccbb345614c0d24c5e21fa931f470cfda874df -Author: Keir Mierle -Date: Wed May 9 05:31:29 2012 -0700 +commit a5353acd85a9fd19370b3d74035d87b0f0bac230 +Author: Petter Strandmark +Date: Tue Aug 28 18:16:41 2012 -0700 - Remove unused template parameter from VariadicEvaluate. + Adding gflags include to test_util.cc + + test_util seems to need gflags. + + Change-Id: I0c4757960f8ac69ad599c138aea58e3c88a4ea28 -commit 82f4b88c34b0b2cf85064e5fc20e374e978b2e3b -Author: Sameer Agarwal -Date: Sun May 6 21:05:28 2012 -0700 +commit 87ca1b2ba28ec512752bbcf5fc994ce1434eb765 +Author: Petter Strandmark +Date: Tue Aug 28 18:05:20 2012 -0700 - Extend support writing linear least squares problems to disk. + Changing random.h to use cstdlib for Windows compability. - 1. Make the mechanism for writing problems to disk, generic and - controllable using an enum DumpType visible in the API. + As discussed with Sameer today. - 2. Instead of single file containing protocol buffers, now matrices can - be written in a matlab/octave friendly format. This is now the default. + Change-Id: If3d0284830c6591c71cc77b8400cafb45c0da61f + +commit aeb00a07323808a0a1816e733ad18a87d5109ea3 +Author: Petter Strandmark +Date: Mon Aug 27 22:22:57 2012 -0700 + + Removing gomp for Visual Studio - 3. The support for writing problems to disk is moved into - linear_least_squares_problem.cc/h + Linking currently fails in Visual Studio due to a missing library + "gomp.lib". This is not needed in Visual Studio. OpenMP works + without it. + + Change-Id: I39e204a8dd4f1b7425df7d4b222d86a8bb961432 + +commit 6f362464ba99b800494d2f15c27768a342ddaa68 +Author: Markus Moll +Date: Tue Aug 28 01:03:38 2012 +0200 + + Add some tests for DoglegStrategy. - 4. SparseMatrix now has a ToTextFile virtual method which is - implemented by each of its subclasses to write a (i,j,s) triplets. + Not necessarily a complete set. - 5. Minor changes to simple_bundle_adjuster to enable logging at startup. + Change-Id: I14eb3a38c6fe976c8212f3934655411b6d1e0aa4 -commit d297f8d3d3f5025c24752f0f4c1ec2469a769f99 -Merge: 7e74d81 f8bd7fa -Author: Keir Mierle -Date: Tue May 8 05:39:56 2012 -0700 +commit 122cf836a6dc9726489ce2fbecc6143bddc1caaf +Author: Sameer Agarwal +Date: Fri Aug 24 16:28:27 2012 -0700 - Merge branch 'master' into windows + Documentation update. + + Change-Id: I0a3c5ae4bc981a8f5bdd5a8905f923dc5f09a024 -commit f8bd7fa9aa9dbf64b6165606630287cf8cf21194 +commit 69081719f73da8de2935774a42d237837a91952a Author: Keir Mierle -Date: Tue May 8 05:39:32 2012 -0700 +Date: Mon Aug 27 13:28:56 2012 -0700 - Small tweaks to the block jacobi preconditioner. + Remove unnecessary overload for hash<> + + The overload for pointers in hash tables was applied in normal + usage of schur_ordering.cc. However, the tests did not include the + overload since they only included collections_port.h. As a result, + the routines in schur_ordering.cc were using a different hash + function than that inside the tests. + + The fix is to remove the specialization. If this breaks one of the + compiler configurations, we will find a workaround at that time. + + Change-Id: Idbf60415d5e2aec0c865b514ad0c577d21b91405 -commit 7e74d81ad57a159f14110eb5348b3bc7990b8bd4 -Merge: ecd7c8d e2a6cdc -Author: Keir Mierle -Date: Mon May 7 07:02:49 2012 -0700 +commit 1762420b6ed76b1c4d30b913b2cac1927b666534 +Author: Sameer Agarwal +Date: Wed Aug 22 10:01:31 2012 -0700 - Merge branch 'master' into windows + Update changelog. + + Change-Id: Idf5af69d5a9dbe35f58e30a8afcbfcd29bb7ebfe -commit e2a6cdc0816af9d0c77933f5017f137da3d52a35 +commit 976ab7aca908309b8282cb40bc080ca859136854 Author: Keir Mierle -Date: Mon May 7 06:39:56 2012 -0700 +Date: Thu Aug 23 18:21:36 2012 -0700 - Address some of the comments on CGNR patch + Remove Google-era vestigial unit test. - - Rename BlockDiagonalPreconditioner to BlockJacobiPreconditioner - - Include the diagonal in the block jacobi preconditioner. - - Better flag help for eta. - - Enable test for CGNR - - Rename CONJUGATE_GRADIENTS to CGNR. - - etc. + Change-Id: Ia7a295a5c759a17c1675a3055d287d3e40e9e0fe -commit 1b95dc580aa5d89be021c0915e26df83f18013bb -Merge: 211812a 7646039 +commit 6ad6257de0e2152ac5e77dc003758de45187d6ea Author: Keir Mierle -Date: Mon May 7 04:34:10 2012 -0700 +Date: Wed Aug 22 11:10:31 2012 -0700 - Merge branch 'master' of https://code.google.com/p/ceres-solver + Add a workaround for an Android NDK compiler bug. + + On certain NDK build configurations, one of the innermost + parts of the Schur eliminator would get compiled + incorrectly. The compiler changed a -= to a +=. + + The normal Ceres unit tests caught the problem; however, + since it is not possible to build the tests with the NDK + (only with the standalone toolchain) this was difficult to + track down. Finding the issue involved pasting the schur + eliminator unit test inside of solver_impl.cc and other such + hacks. + + Change-Id: Ie91bb545d74fe39f0c8cbd1a6eb69ee4d8b25fb2 -commit 211812a57360d2011cbcfd115cd55e0eb73600db -Author: Keir Mierle -Date: Mon May 7 04:33:50 2012 -0700 +commit aecb2dc92b4aa7f3bf77a1ac918e62953602392b +Author: Sameer Agarwal +Date: Wed Aug 22 10:08:17 2012 -0700 - Better error handling in bundle_adjuster.cc + Fix relative path bug in bibtex call. + + Change-Id: I0d31786564320a6831259bcdf4c75a6b665c43ad -commit 7646039ad9672b267495f5b31925473ad3022ac8 +commit 1e2892009e591804df6286caebd5c960e7e3b099 Author: Sameer Agarwal -Date: Sun May 6 22:02:19 2012 -0700 +Date: Tue Aug 21 18:00:54 2012 -0700 - Kashif's corrections to the docs + Update Summary::FullReport to report dogleg type. + + Change-Id: I0b4be8d7486c1c4b36b299693b3fe8b0d3426537 -commit 0d2d34148d10c5c7e924b3ca82ad2b237573ef64 +commit 295ade1122a86b83e1ea605d5ca394f315874717 Author: Sameer Agarwal -Date: Sun May 6 21:16:03 2012 -0700 +Date: Wed Aug 22 06:51:22 2012 -0700 - glog minimum version requirements + Fix Eigen3 Row/Column Major storage issue. - Building Ceres requires version 0.3.1 or better of glog. - Fedora 16 ships with a busted version 0.3. + Eigen3 does not allow column vectors to be stored in row-major + format. NumericDiffCostFunction by default stores its Jacobian + matrices in row-major format. This works fine if the residual + contains more than one variable. But if the residual block + depends on one variable and has more than one residuals, the + resulting Jacobian matrix is a column matrix in row-major format + resulting in a compile time error. - issue 15 contains the gory details. + The fix is to check the template parameters and switch to column-major + storage as needed. - Added a note to the build documentation to this effect. + Thanks to Lena Gieseke for reporting this. + + Change-Id: Icc51c5b38e1f3609e0e1ecb3c4e4a02aecd72c3b -commit 39efc5ec4b64b8f5a2c5a3dbacdbc45421221547 -Author: Keir Mierle -Date: Sun May 6 16:09:52 2012 -0700 +commit 9ad27e8e9fb1bbd2054e2f6ae37623e01428f1c0 +Author: Arnaud Gelas +Date: Tue Aug 21 09:56:30 2012 +0200 - Fix tests broken by the CGNR change. + Add one uninstall target to remove all installed files + + Change-Id: Ifcf89a6c27b25f28403d95a50e29c093a525298f -commit 3faa08b7f7c4ac73661c6a15a6824c12080dfcb1 -Author: Sameer Agarwal -Date: Sun May 6 16:08:22 2012 -0700 +commit 0c3a748ee49e04fe334f8f5a433649d18003d550 +Author: Markus Moll +Date: Tue Aug 21 14:44:59 2012 +0200 - Formatting fixed based on Keir's comments and extended the tests + Allow equal lower and upper bound for diagonal scaling. + + This way, setting the lower and upper bound both to 1.0, one can disable + the automatic trust region scaling. + + Change-Id: Ifa317a6911b813a89c1cf7fdfde25af603705319 -commit 4f21c68409bc478c431a9b6aedf9e5cfdf11d2f3 -Author: Sameer Agarwal -Date: Sun May 6 15:33:47 2012 -0700 +commit 3d644b76adefac6475b91dc53c3ae5e01c4f4d66 +Author: Arnaud Gelas +Date: Thu Aug 16 17:33:21 2012 +0200 - Fix the struct weak ordering used by independent set ordering, tests for it + Install headers, libraries and pdf + + Headers are installed in ${CMAKE_INSTALL_PREFIX}/include/ceres + Libraries are installed in ${CMAKE_INSTALL_PREFIX}/lib + pdf is installed in ${CMAKE_INSTALL_PREFIX}/share/ceres/docs + + Change-Id: Ic175f2c2f5fa86820a1e8c64c2ed171f4a302a68 -commit 887b156b917ccd4c172484452b059d33ea45f4f0 -Author: Sameer Agarwal -Date: Sun May 6 15:14:47 2012 -0700 +commit d2fb5adea4d8c2aeb43c4289c6976798a54d3cf1 +Author: Arnaud Gelas +Date: Fri Aug 17 10:11:02 2012 +0200 - fix he degree ordering routine + Configure gerrit hook at CMake time + + If the source directory is a clone, at CMake time the commit-msg hook gets + downloaded and installed in the right location. + + Change-Id: I5fee17d050ca22d8b92a49fdcc2a1cd6659f209b -commit ecd7c8df2af19404dc394b36bbe96e9db3bce840 -Author: Keir Mierle -Date: Sun May 6 00:09:41 2012 -0700 +commit 73166098fc4b1072adc30321c666188a3909c43c +Author: Arnaud Gelas +Date: Mon Aug 20 15:40:41 2012 +0200 - First step towards windows compatibilty + Add one CMake option to build the examples. + + Currently the examples are always built. For external projects, it is useful + not to compile the examples. - This adds some small changes to Ceres to make it mostly - compile on Windows. There are still issues with the - hash map use in schur_ordering.cc but I will fix those - shortly. + Change-Id: I41d3bde19c7e742818e60f78222d39c43992ca8b -commit f7898fba1b92f0e996571b5bfa22a37f5e3644de +commit 86d4f1ba41ef14eb1b6b61a7936af83387b35eb2 Author: Keir Mierle -Date: Sat May 5 20:55:08 2012 -0700 +Date: Mon Aug 20 11:52:04 2012 -0700 - Add a general sparse iterative solver: CGNR + Add missing return statement. - This adds a new LinearOperator which implements symmetric - products of a matrix, and a new CGNR solver to leverage - CG to directly solve the normal equations. This also - includes a block diagonal preconditioner. In experiments - on problem-16, the non-preconditioned version is about - 1/5 the speed of SPARSE_SCHUR, and the preconditioned - version using block cholesky is about 20% slower than - SPARSE_SCHUR. + Change-Id: I5eaf718318e27040e3c97e32ee46cf0a11176a37 -commit 0a359d6198d257776a8831c3eb98f64ee91cf836 +commit 51eb229da34187a4e8ce73ed9cc0e731998bb2be Author: Keir Mierle -Date: Sat May 5 20:33:46 2012 -0700 +Date: Mon Aug 20 11:46:12 2012 -0700 - Comment formatting. + Add Program::ToString() to aid debugging. + + Change-Id: I0ab37ed2fe0947ca87a152919d4e7dc9b56dedc6 -commit db4ec9312bb2f1ca7b2337812f6bad6cdd75b227 +commit bcc7100635e2047dc2b77df19a4ded8a6ab4d4b9 Author: Keir Mierle -Date: Sat May 5 20:33:16 2012 -0700 +Date: Mon Aug 20 11:45:04 2012 -0700 - Comment formatting + Ignore minted.sty. + + Change-Id: I2467a6f801812b9007b51bf14b00757f026e4322 -commit f10163aaf3e57f52551bcd60bbdae873890a49dd +commit 9705a736dd3d6fbead0d8a6ff77102c69bbcdc08 Author: Keir Mierle -Date: Fri May 4 21:33:53 2012 -0700 +Date: Mon Aug 20 11:24:05 2012 -0700 - Warn about disabled schur specializations. + Add ParameterBlock::ToString() to aid debugging. - This commit brought to you from 30,000ft. + Change-Id: Id3f5cb27b855c536dd65a986f345bd8eb2799dfa -commit ad7b2b4aaf3ccc51f2b854febd53a9df54686cfe -Author: Keir Mierle -Date: Fri May 4 20:15:28 2012 -0700 +commit 0c714a70e6123ceb68e5cfcd3cfbee0d09deb1db +Author: Sameer Agarwal +Date: Mon Aug 20 11:18:16 2012 -0700 + + Fix blanks before private in loss_function.h + + Change-Id: I068bed6431bc7c9b7958af391655df61499000b2 + +commit 51cf7cbe3bac45c6807c2703a2fc3175d76a1b47 +Author: Markus Moll +Date: Mon Aug 20 20:10:20 2012 +0200 + + Add the two-dimensional subspace search to DoglegStrategy + + Change-Id: I5163744c100cdf07dd93343d0734ffe0e80364f3 - Add vim swapfiles to .gitignore +commit ad1f7b772e559a911ac3a3b078b0aee1836fe785 +Author: Sameer Agarwal +Date: Mon Aug 20 11:10:34 2012 -0700 + + Add ArcTanLoss, TolerantLoss and ComposedLossFunction. + + Based on work by James Roseborough. + + Change-Id: Idc4e0b099028f67702bfc7fe3e43dbd96b6f9256 -commit 6447219826bf6e47b0c99d9ff0eaf5e2ba573d79 +commit 05292bf8fc5208b86b4a13544615b584f6efa936 Author: Sameer Agarwal -Date: Thu May 3 21:53:07 2012 -0700 +Date: Mon Aug 20 07:40:45 2012 -0700 + + Add a TrustRegionStrategy::Summary object. + + Change-Id: I7caee35a3408ee4a0ec16ba407410d822929340d - 1. Changes the tutorial to refer to BriefReport. - 2. Some of the enums have commas at the end. - 3. Fix a bug in the default value of circle_fit.cc in the examples. +commit b12b906c4d21c3949f0dce62c4c0d083c8edecf1 +Author: Arnaud Gelas +Date: Wed Aug 15 16:27:38 2012 +0200 -commit 30c5f93c7f88dec49f76168663372772e06f17f5 + Add one option to generate the PDF from CMake at build time + + Make sure pygmentize is installed + + Change-Id: I068ba45c33a8e96acc906a464b12d10d58b3e231 + +commit b9f15a59361c609ffc4a328aea9be3d265b5da81 Author: Sameer Agarwal -Date: Thu May 3 10:44:43 2012 -0700 +Date: Sat Aug 18 13:06:19 2012 -0700 + + Add a dense Cholesky factorization based linear solver. + + For problems with a small number of variables, but a large + number of residuals, it is sometimes beneficial to use the + Cholesky factorization on the normal equations, instead of + the dense QR factorization of the Jacobian, even though it + is numerically the better thing to do. + + Change-Id: I3506b006195754018deec964e6e190b7e8c9ac8f - Rework the glog and gtest path checking to be consistent with the rest of the file and disable the dashboard support enabled by the earlier ctesting related patch. +commit b3fa009435acf476cd373052e62988f6437970b1 +Author: Arnaud Gelas +Date: Fri Aug 17 10:31:41 2012 +0200 -commit f10b033eb4aca77919987bc551d16d8a88b10110 -Merge: cc38774 e0a52a9 + Set CMAKE_*_OUTPUT_DIRECTORY + + Gather + * all executables in ${CMAKE_BINARY_DIR}/bin + * all libraries (static and dynamic) in ${CMAKE_BINARY_DIR}/lib + + Change-Id: Ibc2fa1adfb6f0aea65d66d570259b79546bf3b07 + +commit 1b8a4d5d11671ed83cf6077e363dd95333f08ef8 Author: Sameer Agarwal -Date: Thu May 3 08:45:20 2012 -0700 +Date: Fri Aug 17 16:49:11 2012 -0700 + + Fix a minor bug in detect_structure logging. + + Change-Id: I117f7745e4c67595b3ff9244cde82b5b5b34ee4b - Merge branch 'ctest' +commit 31c1e784ab2cb9294c6e05414cf06aae2b3766de +Author: Keir Mierle +Date: Fri Aug 17 16:16:32 2012 -0700 + + Minor cleanups. + + Change-Id: Ida4866997deeaa1bc2cebd6b69313a05ac82e457 -commit e0a52a993394e73bc7f7db8d520728926feab83e +commit e83f7879a8b21c6976e116958caf35bcdcf41cb0 Author: Sameer Agarwal -Date: Thu May 3 08:43:34 2012 -0700 +Date: Fri Aug 17 15:34:42 2012 -0700 - Arnaus Gelas' patch to add better path searching for gflags and glog + Fix SuiteSparse3 UFConfig.h detection really. + + Change-Id: Id187102e755b7d778dff4363f22f9a4697ed12dd -commit a9b8e815e1c026599734510399b10f4cf014c9cd +commit 96f25dc57658d296ee6b6633818b4f1e51d7d587 Author: Sameer Agarwal -Date: Thu May 3 08:41:52 2012 -0700 +Date: Fri Aug 17 15:34:42 2012 -0700 + + Fix SuiteSparse3 UFConfig.h detection. + + Change-Id: Ia59aefdb0ad7f713f76ed79692f2db4fa2821e5b + +commit c497bd6cd9aa944f518aa491d3bc645851ff9594 +Author: Markus Moll +Date: Fri Aug 17 14:40:13 2012 +0200 - Arnaus Gelas' patch to add .gitignore + Add UFconfig and/or SuiteSparse_config test to CMakeLists.txt + + SuiteSparse 4 requires linking to libsuitesparseconfig.a. + Both SuiteSparse 3 and SuiteSparse 4 require an additional header + (either UFconfig.h or SuiteSparse_config.h) that is not found if it is + in a separate path. Therefore, add explicit checks. + + Change-Id: I699902b5db4f1b7f17134b5a54f9aa681445e294 -commit a0cefc3347c32b2065053bbaff4f34d11529d931 +commit 383c04f4236d92801c7c674892814362dedf7ad6 Author: Sameer Agarwal -Date: Thu May 3 08:38:33 2012 -0700 +Date: Fri Aug 17 10:14:04 2012 -0700 - Arnaus Gelas' patch to move to Ctest + Fix QuaternionToAngleAxis to ensure rotations are between -pi and pi. + + Thanks to Guoxuan Zhang for reporting this. + + Change-Id: I2831ca3a04d5dc6467849c290461adbe23faaea3 -commit cc38774d74e287704915282425fbd16818a72ec3 -Author: Keir Mierle -Date: Thu May 3 01:27:50 2012 -0700 +commit dd2b17d7dd9750801ba4720bdece2062e59b7ae3 +Author: Sameer Agarwal +Date: Thu Aug 16 19:34:57 2012 -0700 - Clarify ProgramEvaluator comments. + CERES_DONT_HAVE_PROTOCOL_BUFFERS -> CERES_NO_PROTOCOL_BUFFERS. + + Change-Id: I6c9f50e4c006faf4e75a8f417455db18357f3187 -commit 017c9530df557863f78212fb5ccd02814baa9fa8 +commit 8b4cb7aa2c74a0da62c638b2023566aa242af995 Author: Sameer Agarwal -Date: Wed May 2 08:21:59 2012 -0700 +Date: Thu Aug 16 19:26:55 2012 -0700 - Mac OS X build instructions are much simpler, as homebrew takes care of gflags when glog is brought in. Also CMAKE does not need any flags to do the default thing + Fix sparse linear algebra library logging in Summary::FullReport. + + Change-Id: Id2c902dc86c00954fde7749c7b4a67dd94215a31 -commit 92d5ab5f8ae6fe355c30b606a5f230415ee0494b -Author: Keir Mierle -Date: Tue May 1 18:33:08 2012 -0700 +commit 47d26bcd3b38b5ff53b34768c33b499d47b26bd0 +Author: Markus Moll +Date: Thu Aug 16 00:23:38 2012 +0200 - Link BLAS explicitly on non-Mac platforms + Do not implicitly negate the step in the TrustRegionMinimizer. - Fixes issue #3. + In the TrustRegionMinimizer, the step is currently implicitly negated. + This is done so that the linearized residual is |r - J*step|^2, which + corresponds to J*step = r, so neither J nor r have to be modified. + However, it leads to the rather unintuitive situation that the strategy + returns a step in positive gradient direction, which you would expect to + increase the function value. One way is to rename the "step" parameter in + the strategy to "negative_step" and document it. + This patch instead moves the negation inside the strategy, just around + the linear solver call, so that it is done in a local context and easier + to document. + + Change-Id: Idb258149a01f61c64e22128ea221c5a30cd89c89 -commit df3e54eb4a6b001b7f0560a2da73a5bd7f18615e -Author: Keir Mierle -Date: Tue May 1 18:22:51 2012 -0700 +commit 51da590c8457e6664f76fe9813425a0c71351497 +Author: Markus Moll +Date: Fri Aug 17 12:56:09 2012 +0200 + + Remove tmp file + + Change-Id: I07496fafae7b0c5c12cc26ae336e0db3b5592735 + +commit 7006a1f2b1701b8d89b8d1525fc0101943802221 +Author: Sameer Agarwal +Date: Thu Aug 16 18:04:22 2012 -0700 - Fix link order of CHOLMOD + Correct example code in Powell's function example. + + Thanks to Petter Strandmark for pointing this out. - This was working by accident due to dynamic linking. Fixes issue #2. + Change-Id: I967632235dccdb481396e94904bb911c9a1efe1e -commit f477a3835329e2b48eb20c34c631a480b0f0d5bf +commit 57a44b27bc6fc95b4e70fdc25c25c9925a2072a0 Author: Keir Mierle -Date: Tue May 1 18:10:48 2012 -0700 +Date: Thu Aug 16 17:04:50 2012 -0700 - Fix Eigen search paths + Remove unnecessary flags in NDK build. - Fixes issue #1 on http://code.google.com/p/ceres-solver. + Change-Id: Ib5b4d0b7f2d898671252734978c789b8171d96a8 -commit 17fbc8ebb894c1d22bb3b0b02ea1394b580120f8 -Author: Sameer Agarwal -Date: Tue May 1 00:21:19 2012 -0700 +commit f21bee247251a8b2e836c215a84c4668c31d75cd +Author: Keir Mierle +Date: Thu Aug 16 16:27:10 2012 -0700 - Minor changes to the documentation. Formatting, and typos. + Fix for fpclassify.h NDK porting work. + + Change-Id: I69df1b4caf2941ed96a53e35e43ec54073f84f59 -commit 8ebb0730388045570f22b89fe8672c860cd2ad1b +commit 8ceb02cb75b66602de44a35e413225386cb21c27 Author: Keir Mierle -Date: Mon Apr 30 23:09:08 2012 -0700 +Date: Thu Aug 16 14:23:47 2012 -0700 - Initial commit of Ceres Solver. + Add Android NDK build files. + + This adds a Android.mk build that builds a Ceres static library + suitable for embetting in larger Android applications. This is + useful when needing to build Ceres without GPL'd components, since + the standalone toolchain (needed for the CMake Android build) does + not work with STLPort. + + Change-Id: I8d857237f6f82658741017d161b2e31d9a20e5a7 diff --git a/extern/libmv/third_party/ceres/SConscript b/extern/libmv/third_party/ceres/SConscript index c629fa00176..6d0d2cd5c40 100644 --- a/extern/libmv/third_party/ceres/SConscript +++ b/extern/libmv/third_party/ceres/SConscript @@ -20,9 +20,13 @@ defs.append('CERES_HAVE_PTHREAD') defs.append('CERES_HASH_NAMESPACE_START=namespace std { namespace tr1 {') defs.append('CERES_HASH_NAMESPACE_END=}}') defs.append('CERES_NO_SUITESPARSE') -defs.append('CERES_DONT_HAVE_PROTOCOL_BUFFERS') +defs.append('CERES_NO_CXSPARSE') +defs.append('CERES_NO_PROTOCOL_BUFFERS') defs.append('CERES_RESTRICT_SCHUR_SPECIALIZATION') +if 'Mac OS X 10.5' in env['MACOSX_SDK_CHECK']: + defs.append('CERES_NO_TR1') + incs = '. ../../ ../../../Eigen3 ./include ./internal ../gflags' # work around broken hashtable in 10.5 SDK diff --git a/extern/libmv/third_party/ceres/bundle.sh b/extern/libmv/third_party/ceres/bundle.sh index 99aaadd8d87..ccf6d0aca16 100755 --- a/extern/libmv/third_party/ceres/bundle.sh +++ b/extern/libmv/third_party/ceres/bundle.sh @@ -1,6 +1,5 @@ #!/bin/sh -if false; then if [ "x$1" = "x--i-really-know-what-im-doing" ] ; then echo Proceeding as requested by command line ... else @@ -8,16 +7,22 @@ else exit 1 fi -repo="https://code.google.com/p/ceres-solver/" -branch="windows" +repo="https://ceres-solver.googlesource.com/ceres-solver" +branch="master" +tag="1.3.0" tmp=`mktemp -d` +checkout="$tmp/ceres" -GIT="git --git-dir $tmp/ceres/.git --work-tree $tmp/ceres" +GIT="git --git-dir $tmp/ceres/.git --work-tree $checkout" -git clone $repo $tmp/ceres +git clone $repo $checkout if [ $branch != "master" ]; then $GIT checkout -t remotes/origin/$branch +else + if [ "x$tag" != "x" ]; then + $GIT checkout $tag + fi fi $GIT log -n 50 > ChangeLog @@ -37,8 +42,6 @@ done rm -rf $tmp -fi - sources=`find ./include ./internal -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | sed -r 's/^\.\//\t/' | grep -v -E 'schur_eliminator_[0-9]_[0-9]_[0-9d].cc' | sort -d` generated_sources=`find ./include ./internal -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | sed -r 's/^\.\//#\t\t/' | grep -E 'schur_eliminator_[0-9]_[0-9]_[0-9d].cc' | sort -d` headers=`find ./include ./internal -type f -iname '*.h' | sed -r 's/^\.\//\t/' | sort -d` @@ -114,13 +117,13 @@ cat > CMakeLists.txt << EOF set(INC . - ../../../Eigen3 include internal ../gflags ) set(INC_SYS + ../../../Eigen3 ) set(SRC @@ -142,7 +145,7 @@ if(WIN32) if(NOT MINGW) list(APPEND INC - third_party/msinttypes + ../msinttypes ) endif() else() @@ -153,13 +156,32 @@ endif() add_definitions( -DCERES_HAVE_PTHREAD - -D"CERES_HASH_NAMESPACE_START=namespace std { namespace tr1 {" - -D"CERES_HASH_NAMESPACE_END=}}" -DCERES_NO_SUITESPARSE - -DCERES_DONT_HAVE_PROTOCOL_BUFFERS + -DCERES_NO_CXSPARSE + -DCERES_NO_PROTOCOL_BUFFERS -DCERES_RESTRICT_SCHUR_SPECIALIZATION ) +if(MSVC10) + add_definitions( + -D"CERES_HASH_NAMESPACE_START=namespace std {" + -D"CERES_HASH_NAMESPACE_END=}" + ) +else() + add_definitions( + -D"CERES_HASH_NAMESPACE_START=namespace std { namespace tr1 {" + -D"CERES_HASH_NAMESPACE_END=}}" + ) +endif() + +if(APPLE) + if(CMAKE_OSX_DEPLOYMENT_TARGET STREQUAL "10.5") + add_definitions( + -DCERES_NO_TR1 + ) + endif() +endif() + blender_add_lib(extern_ceres "\${SRC}" "\${INC}" "\${INC_SYS}") EOF @@ -186,11 +208,20 @@ defs.append('CERES_HAVE_PTHREAD') defs.append('CERES_HASH_NAMESPACE_START=namespace std { namespace tr1 {') defs.append('CERES_HASH_NAMESPACE_END=}}') defs.append('CERES_NO_SUITESPARSE') -defs.append('CERES_DONT_HAVE_PROTOCOL_BUFFERS') +defs.append('CERES_NO_CXSPARSE') +defs.append('CERES_NO_PROTOCOL_BUFFERS') defs.append('CERES_RESTRICT_SCHUR_SPECIALIZATION') +if 'Mac OS X 10.5' in env['MACOSX_SDK_CHECK']: + defs.append('CERES_NO_TR1') + incs = '. ../../ ../../../Eigen3 ./include ./internal ../gflags' +# work around broken hashtable in 10.5 SDK +if env['OURPLATFORM'] == 'darwin' and env['WITH_BF_BOOST']: + incs += ' ' + env['BF_BOOST_INC'] + defs.append('CERES_HASH_BOOST') + if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'): if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): incs += ' ../msinttypes' diff --git a/extern/libmv/third_party/ceres/files.txt b/extern/libmv/third_party/ceres/files.txt index e9d7f585260..55083572977 100644 --- a/extern/libmv/third_party/ceres/files.txt +++ b/extern/libmv/third_party/ceres/files.txt @@ -2,6 +2,8 @@ include/ceres/autodiff_cost_function.h include/ceres/ceres.h include/ceres/conditioned_cost_function.h include/ceres/cost_function.h +include/ceres/crs_matrix.h +include/ceres/fpclassify.h include/ceres/internal/autodiff.h include/ceres/internal/eigen.h include/ceres/internal/fixed_array.h @@ -20,6 +22,8 @@ include/ceres/rotation.h include/ceres/sized_cost_function.h include/ceres/solver.h include/ceres/types.h +internal/ceres/array_utils.cc +internal/ceres/array_utils.h internal/ceres/block_evaluate_preparer.cc internal/ceres/block_evaluate_preparer.h internal/ceres/block_jacobian_writer.cc @@ -52,13 +56,19 @@ internal/ceres/conjugate_gradients_solver.cc internal/ceres/conjugate_gradients_solver.h internal/ceres/corrector.cc internal/ceres/corrector.h +internal/ceres/cxsparse.cc +internal/ceres/cxsparse.h internal/ceres/dense_jacobian_writer.h +internal/ceres/dense_normal_cholesky_solver.cc +internal/ceres/dense_normal_cholesky_solver.h internal/ceres/dense_qr_solver.cc internal/ceres/dense_qr_solver.h internal/ceres/dense_sparse_matrix.cc internal/ceres/dense_sparse_matrix.h internal/ceres/detect_structure.cc internal/ceres/detect_structure.h +internal/ceres/dogleg_strategy.cc +internal/ceres/dogleg_strategy.h internal/ceres/evaluator.cc internal/ceres/evaluator.h internal/ceres/file.cc @@ -79,6 +89,7 @@ internal/ceres/generated/schur_eliminator_4_4_3.cc internal/ceres/generated/schur_eliminator_4_4_4.cc internal/ceres/generated/schur_eliminator_4_4_d.cc internal/ceres/generated/schur_eliminator_d_d_d.cc +internal/ceres/generate_eliminator_specialization.py internal/ceres/gradient_checking_cost_function.cc internal/ceres/gradient_checking_cost_function.h internal/ceres/graph_algorithms.h @@ -88,8 +99,8 @@ internal/ceres/implicit_schur_complement.h internal/ceres/integral_types.h internal/ceres/iterative_schur_complement_solver.cc internal/ceres/iterative_schur_complement_solver.h -internal/ceres/levenberg_marquardt.cc -internal/ceres/levenberg_marquardt.h +internal/ceres/levenberg_marquardt_strategy.cc +internal/ceres/levenberg_marquardt_strategy.h internal/ceres/linear_least_squares_problems.cc internal/ceres/linear_least_squares_problems.h internal/ceres/linear_operator.cc @@ -106,6 +117,8 @@ internal/ceres/normal_prior.cc internal/ceres/parameter_block.h internal/ceres/partitioned_matrix_view.cc internal/ceres/partitioned_matrix_view.h +internal/ceres/polynomial_solver.cc +internal/ceres/polynomial_solver.h internal/ceres/problem.cc internal/ceres/problem_impl.cc internal/ceres/problem_impl.h @@ -136,6 +149,7 @@ internal/ceres/sparse_matrix.h internal/ceres/sparse_normal_cholesky_solver.cc internal/ceres/sparse_normal_cholesky_solver.h internal/ceres/split.cc +internal/ceres/split.h internal/ceres/stl_util.h internal/ceres/stringprintf.cc internal/ceres/stringprintf.h @@ -143,6 +157,10 @@ internal/ceres/suitesparse.cc internal/ceres/suitesparse.h internal/ceres/triplet_sparse_matrix.cc internal/ceres/triplet_sparse_matrix.h +internal/ceres/trust_region_minimizer.cc +internal/ceres/trust_region_minimizer.h +internal/ceres/trust_region_strategy.cc +internal/ceres/trust_region_strategy.h internal/ceres/types.cc internal/ceres/visibility_based_preconditioner.cc internal/ceres/visibility_based_preconditioner.h diff --git a/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h b/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h index e86d6993864..da9ee2c7993 100644 --- a/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h +++ b/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h @@ -163,7 +163,7 @@ class AutoDiffCostFunction : explicit AutoDiffCostFunction(CostFunctor* functor) : functor_(functor) { CHECK_NE(M, DYNAMIC) << "Can't run the fixed-size constructor if the " - << "number of residuals is set to ceres::DYNAMIC."; + << "number of residuals is set to ceres::DYNAMIC."; } // Takes ownership of functor. Ignores the template-provided number of @@ -174,7 +174,7 @@ class AutoDiffCostFunction : AutoDiffCostFunction(CostFunctor* functor, int num_residuals) : functor_(functor) { CHECK_EQ(M, DYNAMIC) << "Can't run the dynamic-size constructor if the " - << "number of residuals is not ceres::DYNAMIC."; + << "number of residuals is not ceres::DYNAMIC."; SizedCostFunction::set_num_residuals(num_residuals); } diff --git a/extern/libmv/third_party/ceres/include/ceres/cost_function.h b/extern/libmv/third_party/ceres/include/ceres/cost_function.h index 84403d90636..9b010f78f9d 100644 --- a/extern/libmv/third_party/ceres/include/ceres/cost_function.h +++ b/extern/libmv/third_party/ceres/include/ceres/cost_function.h @@ -119,7 +119,7 @@ class CostFunction { // number of outputs (residuals). vector parameter_block_sizes_; int num_residuals_; - DISALLOW_COPY_AND_ASSIGN(CostFunction); + CERES_DISALLOW_COPY_AND_ASSIGN(CostFunction); }; } // namespace ceres diff --git a/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h b/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h new file mode 100644 index 00000000000..c9fe8f78b7c --- /dev/null +++ b/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h @@ -0,0 +1,65 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#ifndef CERES_PUBLIC_CRS_MATRIX_H_ +#define CERES_PUBLIC_CRS_MATRIX_H_ + +#include +#include "ceres/internal/port.h" + +namespace ceres { + +// A compressed row sparse matrix used primarily for communicating the +// Jacobian matrix to the user. +struct CRSMatrix { + CRSMatrix() : num_rows(0), num_cols(0) {} + + int num_rows; + int num_cols; + + // A compressed row matrix stores its contents in three arrays. + // The non-zero pattern of the i^th row is given by + // + // rows[cols[i] ... cols[i + 1]] + // + // and the corresponding values by + // + // values[cols[i] ... cols[i + 1]] + // + // Thus, cols is a vector of size num_cols + 1, and rows and values + // have as many entries as number of non-zeros in the matrix. + vector cols; + vector rows; + vector values; +}; + +} // namespace ceres + +#endif // CERES_PUBLIC_CRS_MATRIX_H_ diff --git a/extern/libmv/third_party/ceres/include/ceres/fpclassify.h b/extern/libmv/third_party/ceres/include/ceres/fpclassify.h new file mode 100644 index 00000000000..5a9ea1599d2 --- /dev/null +++ b/extern/libmv/third_party/ceres/include/ceres/fpclassify.h @@ -0,0 +1,88 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: keir@google.com (Keir Mierle) +// +// Portable floating point classification. The names are picked such that they +// do not collide with macros. For example, "isnan" in C99 is a macro and hence +// does not respect namespaces. +// +// TODO(keir): Finish porting! + +#ifndef CERES_PUBLIC_FPCLASSIFY_H_ +#define CERES_PUBLIC_FPCLASSIFY_H_ + +#if defined(_MSC_VER) +#include +#endif + +namespace ceres { + +#if defined(_MSC_VER) +inline bool IsFinite (double x) { return _finite(x); } +inline bool IsInfinite(double x) { return !_finite(x) && !_isnan(x); } +inline bool IsNaN (double x) { return _isnan(x); } +inline bool IsNormal (double x) { + int classification = _fpclass(x); + return classification == _FPCLASS_NN || + classification == _FPCLASS_PN; +} +#elif defined(ANDROID) + +// On Android when using the GNU STL, the C++ fpclassify functions are not +// available. Strictly speaking, the std functions are are not standard until +// C++11. Instead use the C99 macros on Android. +inline bool IsNaN (double x) { return isnan(x); } +inline bool IsNormal (double x) { return isnormal(x); } + +// On Android NDK r6, when using STLPort, the isinf and isfinite functions are +// not available, so reimplement them. +# if defined(_STLPORT_VERSION) +inline bool IsInfinite(double x) { + return x == std::numeric_limits::infinity() || + x == -std::numeric_limits::infinity(); +} +inline bool IsFinite(double x) { + return !isnan(x) && !IsInfinite(x); +} +# else +inline bool IsFinite (double x) { return isfinite(x); } +inline bool IsInfinite(double x) { return isinf(x); } +# endif // defined(_STLPORT_VERSION) +#else +// These definitions are for the normal Unix suspects. +// TODO(keir): Test the "else" with more platforms. +inline bool IsFinite (double x) { return std::isfinite(x); } +inline bool IsInfinite(double x) { return std::isinf(x); } +inline bool IsNaN (double x) { return std::isnan(x); } +inline bool IsNormal (double x) { return std::isnormal(x); } +#endif + +} // namespace ceres + +#endif // CERES_PUBLIC_FPCLASSIFY_H_ diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h b/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h index 84617c4fa06..ce777d22dc7 100644 --- a/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h +++ b/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h @@ -34,6 +34,8 @@ #include #include +#include "Eigen/Core" +#include "ceres/internal/macros.h" #include "ceres/internal/manual_constructor.h" namespace ceres { @@ -136,7 +138,6 @@ class FixedArray { // and T must be the same, otherwise callers' assumptions about use // of this code will be broken. struct InnerContainer { - EIGEN_MAKE_ALIGNED_OPERATOR_NEW T element; }; diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/macros.h b/extern/libmv/third_party/ceres/include/ceres/internal/macros.h index 0cfd773bcca..83ec31193e7 100644 --- a/extern/libmv/third_party/ceres/include/ceres/internal/macros.h +++ b/extern/libmv/third_party/ceres/include/ceres/internal/macros.h @@ -43,11 +43,13 @@ // // For disallowing only assign or copy, write the code directly, but declare // the intend in a comment, for example: -// void operator=(const TypeName&); // DISALLOW_ASSIGN -// Note, that most uses of DISALLOW_ASSIGN and DISALLOW_COPY are broken -// semantically, one should either use disallow both or neither. Try to -// avoid these in new code. -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ +// +// void operator=(const TypeName&); // _DISALLOW_ASSIGN + +// Note, that most uses of CERES_DISALLOW_ASSIGN and CERES_DISALLOW_COPY +// are broken semantically, one should either use disallow both or +// neither. Try to avoid these in new code. +#define CERES_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&); \ void operator=(const TypeName&) @@ -57,9 +59,9 @@ // This should be used in the private: declarations for a class // that wants to prevent anyone from instantiating it. This is // especially useful for classes containing only static methods. -#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ +#define CERES_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ TypeName(); \ - DISALLOW_COPY_AND_ASSIGN(TypeName) + CERES_DISALLOW_COPY_AND_ASSIGN(TypeName) // The arraysize(arr) macro returns the # of elements in an array arr. // The expression is a compile-time constant, and therefore can be @@ -151,4 +153,19 @@ char (&ArraySizeHelper(const T (&array)[N]))[N]; #define MUST_USE_RESULT #endif +// Platform independent macros to get aligned memory allocations. +// For example +// +// MyFoo my_foo CERES_ALIGN_ATTRIBUTE(16); +// +// Gives us an instance of MyFoo which is aligned at a 16 byte +// boundary. +#if defined(_MSC_VER) +#define CERES_ALIGN_ATTRIBUTE(n) __declspec(align(n)) +#define CERES_ALIGN_OF(T) __alignof(T) +#elif defined(__GNUC__) +#define CERES_ALIGN_ATTRIBUTE(n) __attribute__((aligned(n))) +#define CERES_ALIGN_OF(T) __alignof(T) +#endif + #endif // CERES_PUBLIC_INTERNAL_MACROS_H_ diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h b/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h index a1d1f444e36..174d35ee2bd 100644 --- a/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h +++ b/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h @@ -45,60 +45,49 @@ namespace ceres { namespace internal { -// ------- Define ALIGNED_CHAR_ARRAY -------------------------------- +// ------- Define CERES_ALIGNED_CHAR_ARRAY -------------------------------- -#ifndef ALIGNED_CHAR_ARRAY +#ifndef CERES_ALIGNED_CHAR_ARRAY // Because MSVC and older GCCs require that the argument to their alignment // construct to be a literal constant integer, we use a template instantiated // at all the possible powers of two. template struct AlignType { }; template struct AlignType<0, size> { typedef char result[size]; }; -#if defined(_MSC_VER) -#define BASE_PORT_H_ALIGN_ATTRIBUTE(X) __declspec(align(X)) -#define BASE_PORT_H_ALIGN_OF(T) __alignof(T) -#elif defined(__GNUC__) -#define BASE_PORT_H_ALIGN_ATTRIBUTE(X) __attribute__((aligned(X))) -#define BASE_PORT_H_ALIGN_OF(T) __alignof__(T) -#endif -#if defined(BASE_PORT_H_ALIGN_ATTRIBUTE) +#if !defined(CERES_ALIGN_ATTRIBUTE) +#define CERES_ALIGNED_CHAR_ARRAY you_must_define_CERES_ALIGNED_CHAR_ARRAY_for_your_compiler +#else // !defined(CERES_ALIGN_ATTRIBUTE) -#define BASE_PORT_H_ALIGNTYPE_TEMPLATE(X) \ +#define CERES_ALIGN_TYPE_TEMPLATE(X) \ template struct AlignType { \ - typedef BASE_PORT_H_ALIGN_ATTRIBUTE(X) char result[size]; \ - } - -BASE_PORT_H_ALIGNTYPE_TEMPLATE(1); -BASE_PORT_H_ALIGNTYPE_TEMPLATE(2); -BASE_PORT_H_ALIGNTYPE_TEMPLATE(4); -BASE_PORT_H_ALIGNTYPE_TEMPLATE(8); -BASE_PORT_H_ALIGNTYPE_TEMPLATE(16); -BASE_PORT_H_ALIGNTYPE_TEMPLATE(32); -BASE_PORT_H_ALIGNTYPE_TEMPLATE(64); -BASE_PORT_H_ALIGNTYPE_TEMPLATE(128); -BASE_PORT_H_ALIGNTYPE_TEMPLATE(256); -BASE_PORT_H_ALIGNTYPE_TEMPLATE(512); -BASE_PORT_H_ALIGNTYPE_TEMPLATE(1024); -BASE_PORT_H_ALIGNTYPE_TEMPLATE(2048); -BASE_PORT_H_ALIGNTYPE_TEMPLATE(4096); -BASE_PORT_H_ALIGNTYPE_TEMPLATE(8192); + typedef CERES_ALIGN_ATTRIBUTE(X) char result[size]; \ + } + +CERES_ALIGN_TYPE_TEMPLATE(1); +CERES_ALIGN_TYPE_TEMPLATE(2); +CERES_ALIGN_TYPE_TEMPLATE(4); +CERES_ALIGN_TYPE_TEMPLATE(8); +CERES_ALIGN_TYPE_TEMPLATE(16); +CERES_ALIGN_TYPE_TEMPLATE(32); +CERES_ALIGN_TYPE_TEMPLATE(64); +CERES_ALIGN_TYPE_TEMPLATE(128); +CERES_ALIGN_TYPE_TEMPLATE(256); +CERES_ALIGN_TYPE_TEMPLATE(512); +CERES_ALIGN_TYPE_TEMPLATE(1024); +CERES_ALIGN_TYPE_TEMPLATE(2048); +CERES_ALIGN_TYPE_TEMPLATE(4096); +CERES_ALIGN_TYPE_TEMPLATE(8192); // Any larger and MSVC++ will complain. -#define ALIGNED_CHAR_ARRAY(T, Size) \ - typename AlignType::result +#undef CERES_ALIGN_TYPE_TEMPLATE -#undef BASE_PORT_H_ALIGNTYPE_TEMPLATE -#undef BASE_PORT_H_ALIGN_ATTRIBUTE +#define CERES_ALIGNED_CHAR_ARRAY(T, Size) \ + typename AlignType::result -#else // defined(BASE_PORT_H_ALIGN_ATTRIBUTE) -#define ALIGNED_CHAR_ARRAY you_must_define_ALIGNED_CHAR_ARRAY_for_your_compiler -#endif // defined(BASE_PORT_H_ALIGN_ATTRIBUTE) +#endif // !defined(CERES_ALIGN_ATTRIBUTE) -#undef BASE_PORT_H_ALIGNTYPE_TEMPLATE -#undef BASE_PORT_H_ALIGN_ATTRIBUTE - -#endif // ALIGNED_CHAR_ARRAY +#endif // CERES_ALIGNED_CHAR_ARRAY template class ManualConstructor { @@ -203,10 +192,10 @@ class ManualConstructor { } private: - ALIGNED_CHAR_ARRAY(Type, 1) space_; + CERES_ALIGNED_CHAR_ARRAY(Type, 1) space_; }; -#undef ALIGNED_CHAR_ARRAY +#undef CERES_ALIGNED_CHAR_ARRAY } // namespace internal } // namespace ceres diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/port.h b/extern/libmv/third_party/ceres/include/ceres/internal/port.h index 9a3e5cced58..a9fe247cef5 100644 --- a/extern/libmv/third_party/ceres/include/ceres/internal/port.h +++ b/extern/libmv/third_party/ceres/include/ceres/internal/port.h @@ -31,6 +31,8 @@ #ifndef CERES_PUBLIC_INTERNAL_PORT_H_ #define CERES_PUBLIC_INTERNAL_PORT_H_ +#include + namespace ceres { // It is unfortunate that this import of the entire standard namespace is @@ -39,6 +41,10 @@ namespace ceres { // things outside of the Ceres optimization package. using namespace std; +// This is necessary to properly handle the case that there is a different +// "string" implementation in the global namespace. +using std::string; + } // namespace ceres #endif // CERES_PUBLIC_INTERNAL_PORT_H_ diff --git a/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h b/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h index 88da992d0c5..29157d380f2 100644 --- a/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h +++ b/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h @@ -28,8 +28,9 @@ // // Author: sameeragarwal@google.com (Sameer Agarwal) // -// When an iteration callback is specified, Ceres calls the callback after each -// optimizer step and pass it an IterationSummary object, defined below. +// When an iteration callback is specified, Ceres calls the callback +// after each minimizer step (if the minimizer has not converged) and +// passes it an IterationSummary object, defined below. #ifndef CERES_PUBLIC_ITERATION_CALLBACK_H_ #define CERES_PUBLIC_ITERATION_CALLBACK_H_ @@ -44,7 +45,15 @@ struct IterationSummary { // Current iteration number. int32 iteration; + // Step was numerically valid, i.e., all values are finite and the + // step reduces the value of the linearized model. + // + // Note: step_is_valid is false when iteration = 0. + bool step_is_valid; + // Whether or not the algorithm made progress in this iteration. + // + // Note: step_is_successful is false when iteration = 0. bool step_is_successful; // Value of the objective function. @@ -66,9 +75,10 @@ struct IterationSummary { // cost and the change in the cost of the linearized approximation. double relative_decrease; - // Value of the regularization parameter for Levenberg-Marquardt - // algorithm at the end of the current iteration. - double mu; + // Size of the trust region at the end of the current iteration. For + // the Levenberg-Marquardt algorithm, the regularization parameter + // mu = 1.0 / trust_region_radius. + double trust_region_radius; // For the inexact step Levenberg-Marquardt algorithm, this is the // relative accuracy with which the Newton(LM) step is solved. This @@ -81,13 +91,15 @@ struct IterationSummary { // Newton step. int linear_solver_iterations; - // TODO(sameeragarwal): Change to use a higher precision timer using - // clock_gettime. - // Time (in seconds) spent inside the linear least squares solver. - int iteration_time_sec; + // Time (in seconds) spent inside the minimizer loop in the current + // iteration. + double iteration_time_in_seconds; + + // Time (in seconds) spent inside the trust region step solver. + double step_solver_time_in_seconds; - // Time (in seconds) spent inside the linear least squares solver. - int linear_solver_time_sec; + // Time (in seconds) since the user called Solve(). + double cumulative_time_in_seconds; }; // Interface for specifying callbacks that are executed at the end of @@ -133,7 +145,7 @@ struct IterationSummary { // summary.gradient_max_norm, // summary.step_norm, // summary.relative_decrease, -// summary.mu, +// summary.trust_region_radius, // summary.eta, // summary.linear_solver_iterations); // if (log_to_stdout_) { diff --git a/extern/libmv/third_party/ceres/include/ceres/jet.h b/extern/libmv/third_party/ceres/include/ceres/jet.h index a37870210f1..96e2256fd02 100644 --- a/extern/libmv/third_party/ceres/include/ceres/jet.h +++ b/extern/libmv/third_party/ceres/include/ceres/jet.h @@ -162,16 +162,7 @@ #include #include "Eigen/Core" - -// Visual Studio 2012 or older version -#if defined(_MSC_VER) && _MSC_VER <= 1700 -namespace std { -inline bool isfinite(double x) { return _finite(x); } -inline bool isinf (double x) { return !_finite(x) && !_isnan(x); } -inline bool isnan (double x) { return _isnan(x); } -inline bool isnormal(double x) { return _finite(x) && x != 0.0; } -} // namespace std -#endif +#include "ceres/fpclassify.h" namespace ceres { @@ -184,7 +175,9 @@ struct Jet { // (where T is a Jet). This usually only happens in opt mode. Note that // the C++ standard mandates that e.g. default constructed doubles are // initialized to 0.0; see sections 8.5 of the C++03 standard. - Jet() : a() {} + Jet() : a() { + v.setZero(); + } // Constructor from scalar: a + 0. explicit Jet(const T& value) { @@ -199,18 +192,6 @@ struct Jet { v[k] = T(1.0); } - /* - - // Construct from an array where the first element is the scalar. - // This is templated to support converting from other data types. - template - Jet(const D* scalar_and_derivatives) { - a = T(scalar_and_derivatives[0]); - v = Eigen::Map >( - scalar_and_derivatives + 1, N).cast(); - } - */ - // Compound operators Jet& operator+=(const Jet &y) { *this = *this + y; @@ -232,8 +213,25 @@ struct Jet { return *this; } - T a; // The scalar part. - Eigen::Matrix v; // The infinitesimal part. + // The scalar part. + T a; + + // The infinitesimal part. + // + // Note the Eigen::DontAlign bit is needed here because this object + // gets allocated on the stack and as part of other arrays and + // structs. Forcing the right alignment there is the source of much + // pain and suffering. Even if that works, passing Jets around to + // functions by value has problems because the C++ ABI does not + // guarantee alignment for function arguments. + // + // Setting the DontAlign bit prevents Eigen from using SSE for the + // various operations on Jets. This is a small performance penalty + // since the AutoDiff code will still expose much of the code as + // statically sized loops to the compiler. But given the subtle + // issues that arise due to alignment, especially when dealing with + // multiple platforms, it seems to be a trade off worth making. + Eigen::Matrix v; }; // Unary + @@ -411,10 +409,6 @@ inline double cos (double x) { return std::cos(x); } inline double acos (double x) { return std::acos(x); } inline double sin (double x) { return std::sin(x); } inline double asin (double x) { return std::asin(x); } -inline bool isfinite(double x) { return std::isfinite(x); } -inline bool isinf (double x) { return std::isinf(x); } -inline bool isnan (double x) { return std::isnan(x); } -inline bool isnormal(double x) { return std::isnormal(x); } inline double pow (double x, double y) { return std::pow(x, y); } inline double atan2(double y, double x) { return std::atan2(y, x); } @@ -492,22 +486,23 @@ Jet asin(const Jet& f) { } // Jet Classification. It is not clear what the appropriate semantics are for -// these classifications. This picks that isfinite and isnormal are "all" -// operations, i.e. all elements of the jet must be finite for the jet itself to -// be finite (or normal). For isnan and isinf, the answer is less clear. This -// takes a "any" approach for isnan and isinf such that if any part of a jet is -// nan or inf, then the entire jet is nan or inf. This leads to strange -// situations like a jet can be both isinf and isnan, but in practice the "any" -// semantics are the most useful for e.g. checking that derivatives are sane. +// these classifications. This picks that IsFinite and isnormal are "all" +// operations, i.e. all elements of the jet must be finite for the jet itself +// to be finite (or normal). For IsNaN and IsInfinite, the answer is less +// clear. This takes a "any" approach for IsNaN and IsInfinite such that if any +// part of a jet is nan or inf, then the entire jet is nan or inf. This leads +// to strange situations like a jet can be both IsInfinite and IsNaN, but in +// practice the "any" semantics are the most useful for e.g. checking that +// derivatives are sane. // The jet is finite if all parts of the jet are finite. template inline -bool isfinite(const Jet& f) { - if (!isfinite(f.a)) { +bool IsFinite(const Jet& f) { + if (!IsFinite(f.a)) { return false; } for (int i = 0; i < N; ++i) { - if (!isfinite(f.v[i])) { + if (!IsFinite(f.v[i])) { return false; } } @@ -516,12 +511,12 @@ bool isfinite(const Jet& f) { // The jet is infinite if any part of the jet is infinite. template inline -bool isinf(const Jet& f) { - if (isinf(f.a)) { +bool IsInfinite(const Jet& f) { + if (IsInfinite(f.a)) { return true; } for (int i = 0; i < N; i++) { - if (isinf(f.v[i])) { + if (IsInfinite(f.v[i])) { return true; } } @@ -530,12 +525,12 @@ bool isinf(const Jet& f) { // The jet is NaN if any part of the jet is NaN. template inline -bool isnan(const Jet& f) { - if (isnan(f.a)) { +bool IsNaN(const Jet& f) { + if (IsNaN(f.a)) { return true; } for (int i = 0; i < N; ++i) { - if (isnan(f.v[i])) { + if (IsNaN(f.v[i])) { return true; } } @@ -544,12 +539,12 @@ bool isnan(const Jet& f) { // The jet is normal if all parts of the jet are normal. template inline -bool isnormal(const Jet& f) { - if (!isnormal(f.a)) { +bool IsNormal(const Jet& f) { + if (!IsNormal(f.a)) { return false; } for (int i = 0; i < N; ++i) { - if (!isnormal(f.v[i])) { + if (!IsNormal(f.v[i])) { return false; } } @@ -650,78 +645,6 @@ inline std::ostream &operator<<(std::ostream &s, const Jet& z) { return s << "[" << z.a << " ; " << z.v.transpose() << "]"; } -// A jet traits class to make it easier to work with mixed auto / numeric diff. -template -struct JetOps { - static bool IsScalar() { - return true; - } - static T GetScalar(const T& t) { - return t; - } - static void SetScalar(const T& scalar, T* t) { - *t = scalar; - } - static void ScaleDerivative(double scale_by, T *value) { - // For double, there is no derivative to scale. - } -}; - -template -struct JetOps > { - static bool IsScalar() { - return false; - } - static T GetScalar(const Jet& t) { - return t.a; - } - static void SetScalar(const T& scalar, Jet* t) { - t->a = scalar; - } - static void ScaleDerivative(double scale_by, Jet *value) { - value->v *= scale_by; - } -}; - -template -struct Chain { - static ArgumentType Rule(const FunctionType &f, - const FunctionType dfdx[kNumArgs], - const ArgumentType x[kNumArgs]) { - // In the default case of scalars, there's nothing to do since there are no - // derivatives to propagate. - return f; - } -}; - -// XXX Add documentation here! -template -struct Chain > { - static Jet Rule(const FunctionType &f, - const FunctionType dfdx[kNumArgs], - const Jet x[kNumArgs]) { - // x is itself a function of another variable ("z"); what this function - // needs to return is "f", but with the derivative with respect to z - // attached to the jet. So combine the derivative part of x's jets to form - // a Jacobian matrix between x and z (i.e. dx/dz). - Eigen::Matrix dxdz; - for (int i = 0; i < kNumArgs; ++i) { - dxdz.row(i) = x[i].v.transpose(); - } - - // Map the input gradient dfdx into an Eigen row vector. - Eigen::Map > - vector_dfdx(dfdx, 1, kNumArgs); - - // Now apply the chain rule to obtain df/dz. Combine the derivative with - // the scalar part to obtain f with full derivative information. - Jet jet_f; - jet_f.a = f; - jet_f.v = vector_dfdx.template cast() * dxdz; // Also known as dfdz. - return jet_f; - } -}; - } // namespace ceres namespace Eigen { diff --git a/extern/libmv/third_party/ceres/include/ceres/loss_function.h b/extern/libmv/third_party/ceres/include/ceres/loss_function.h index 81add02cdee..0c0ceaaecd0 100644 --- a/extern/libmv/third_party/ceres/include/ceres/loss_function.h +++ b/extern/libmv/third_party/ceres/include/ceres/loss_function.h @@ -175,6 +175,7 @@ class HuberLoss : public LossFunction { public: explicit HuberLoss(double a) : a_(a), b_(a * a) { } virtual void Evaluate(double, double*) const; + private: const double a_; // b = a^2. @@ -190,6 +191,7 @@ class SoftLOneLoss : public LossFunction { public: explicit SoftLOneLoss(double a) : b_(a * a), c_(1 / b_) { } virtual void Evaluate(double, double*) const; + private: // b = a^2. const double b_; @@ -206,6 +208,7 @@ class CauchyLoss : public LossFunction { public: explicit CauchyLoss(double a) : b_(a * a), c_(1 / b_) { } virtual void Evaluate(double, double*) const; + private: // b = a^2. const double b_; @@ -213,6 +216,78 @@ class CauchyLoss : public LossFunction { const double c_; }; +// Loss that is capped beyond a certain level using the arc-tangent function. +// The scaling parameter 'a' determines the level where falloff occurs. +// For costs much smaller than 'a', the loss function is linear and behaves like +// TrivialLoss, and for values much larger than 'a' the value asymptotically +// approaches the constant value of a * PI / 2. +// +// rho(s) = a atan(s / a). +// +// At s = 0: rho = [0, 1, 0]. +class ArctanLoss : public LossFunction { + public: + explicit ArctanLoss(double a) : a_(a), b_(1 / (a * a)) { } + virtual void Evaluate(double, double*) const; + + private: + const double a_; + // b = 1 / a^2. + const double b_; +}; + +// Loss function that maps to approximately zero cost in a range around the +// origin, and reverts to linear in error (quadratic in cost) beyond this range. +// The tolerance parameter 'a' sets the nominal point at which the +// transition occurs, and the transition size parameter 'b' sets the nominal +// distance over which most of the transition occurs. Both a and b must be +// greater than zero, and typically b will be set to a fraction of a. +// The slope rho'[s] varies smoothly from about 0 at s <= a - b to +// about 1 at s >= a + b. +// +// The term is computed as: +// +// rho(s) = b log(1 + exp((s - a) / b)) - c0. +// +// where c0 is chosen so that rho(0) == 0 +// +// c0 = b log(1 + exp(-a / b) +// +// This has the following useful properties: +// +// rho(s) == 0 for s = 0 +// rho'(s) ~= 0 for s << a - b +// rho'(s) ~= 1 for s >> a + b +// rho''(s) > 0 for all s +// +// In addition, all derivatives are continuous, and the curvature is +// concentrated in the range a - b to a + b. +// +// At s = 0: rho = [0, ~0, ~0]. +class TolerantLoss : public LossFunction { + public: + explicit TolerantLoss(double a, double b); + virtual void Evaluate(double, double*) const; + + private: + const double a_, b_, c_; +}; + +// Composition of two loss functions. The error is the result of first +// evaluating g followed by f to yield the composition f(g(s)). +// The loss functions must not be NULL. +class ComposedLoss : public LossFunction { + public: + explicit ComposedLoss(const LossFunction* f, Ownership ownership_f, + const LossFunction* g, Ownership ownership_g); + virtual ~ComposedLoss(); + virtual void Evaluate(double, double*) const; + + private: + internal::scoped_ptr f_, g_; + const Ownership ownership_f_, ownership_g_; +}; + // The discussion above has to do with length scaling: it affects the space // in which s is measured. Sometimes you want to simply scale the output // value of the robustifier. For example, you might want to weight @@ -249,7 +324,7 @@ class ScaledLoss : public LossFunction { internal::scoped_ptr rho_; const double a_; const Ownership ownership_; - DISALLOW_COPY_AND_ASSIGN(ScaledLoss); + CERES_DISALLOW_COPY_AND_ASSIGN(ScaledLoss); }; // Sometimes after the optimization problem has been constructed, we @@ -314,7 +389,7 @@ class LossFunctionWrapper : public LossFunction { private: internal::scoped_ptr rho_; Ownership ownership_; - DISALLOW_COPY_AND_ASSIGN(LossFunctionWrapper); + CERES_DISALLOW_COPY_AND_ASSIGN(LossFunctionWrapper); }; } // namespace ceres diff --git a/extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h b/extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h index bbaefca5b6c..8544e44d0bc 100644 --- a/extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h +++ b/extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h @@ -93,11 +93,13 @@ struct Differencer { using Eigen::Map; using Eigen::Matrix; using Eigen::RowMajor; + using Eigen::ColMajor; typedef Matrix ResidualVector; typedef Matrix ParameterVector; - typedef Matrix - JacobianMatrix; + typedef Matrix 1) ? ColMajor : RowMajor> JacobianMatrix; Map parameter_jacobian(jacobians[parameter_block], num_residuals, diff --git a/extern/libmv/third_party/ceres/include/ceres/problem.h b/extern/libmv/third_party/ceres/include/ceres/problem.h index 0ca61006bdb..2b08c6723e8 100644 --- a/extern/libmv/third_party/ceres/include/ceres/problem.h +++ b/extern/libmv/third_party/ceres/include/ceres/problem.h @@ -50,13 +50,13 @@ namespace ceres { class CostFunction; class LossFunction; class LocalParameterization; +class Solver; namespace internal { class Preprocessor; class ProblemImpl; class ParameterBlock; class ResidualBlock; -class SolverImpl; } // namespace internal // A ResidualBlockId is a handle clients can use to delete residual @@ -255,9 +255,9 @@ class Problem { int NumResiduals() const; private: - friend class internal::SolverImpl; + friend class Solver; internal::scoped_ptr problem_impl_; - DISALLOW_COPY_AND_ASSIGN(Problem); + CERES_DISALLOW_COPY_AND_ASSIGN(Problem); }; } // namespace ceres diff --git a/extern/libmv/third_party/ceres/include/ceres/rotation.h b/extern/libmv/third_party/ceres/include/ceres/rotation.h index e4227e78b9a..0d8a390d5d1 100644 --- a/extern/libmv/third_party/ceres/include/ceres/rotation.h +++ b/extern/libmv/third_party/ceres/include/ceres/rotation.h @@ -47,6 +47,7 @@ #include #include +#include "glog/logging.h" namespace ceres { @@ -145,18 +146,11 @@ void AngleAxisRotatePoint(const T angle_axis[3], const T pt[3], T result[3]); // --- IMPLEMENTATION -// Duplicate rather than decorate every use of cmath with _USE_MATH_CONSTANTS. -// Necessitated by Windows. -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#define CERES_NEED_M_PI_UNDEF -#endif - template inline void AngleAxisToQuaternion(const T* angle_axis, T* quaternion) { - const T &a0 = angle_axis[0]; - const T &a1 = angle_axis[1]; - const T &a2 = angle_axis[2]; + const T& a0 = angle_axis[0]; + const T& a1 = angle_axis[1]; + const T& a2 = angle_axis[2]; const T theta_squared = a0 * a0 + a1 * a1 + a2 * a2; // For points not at the origin, the full conversion is numerically stable. @@ -183,16 +177,35 @@ inline void AngleAxisToQuaternion(const T* angle_axis, T* quaternion) { template inline void QuaternionToAngleAxis(const T* quaternion, T* angle_axis) { - const T &q1 = quaternion[1]; - const T &q2 = quaternion[2]; - const T &q3 = quaternion[3]; - const T sin_squared = q1 * q1 + q2 * q2 + q3 * q3; + const T& q1 = quaternion[1]; + const T& q2 = quaternion[2]; + const T& q3 = quaternion[3]; + const T sin_squared_theta = q1 * q1 + q2 * q2 + q3 * q3; // For quaternions representing non-zero rotation, the conversion // is numerically stable. - if (sin_squared > T(0.0)) { - const T sin_theta = sqrt(sin_squared); - const T k = T(2.0) * atan2(sin_theta, quaternion[0]) / sin_theta; + if (sin_squared_theta > T(0.0)) { + const T sin_theta = sqrt(sin_squared_theta); + const T& cos_theta = quaternion[0]; + + // If cos_theta is negative, theta is greater than pi/2, which + // means that angle for the angle_axis vector which is 2 * theta + // would be greater than pi. + // + // While this will result in the correct rotation, it does not + // result in a normalized angle-axis vector. + // + // In that case we observe that 2 * theta ~ 2 * theta - 2 * pi, + // which is equivalent saying + // + // theta - pi = atan(sin(theta - pi), cos(theta - pi)) + // = atan(-sin(theta), -cos(theta)) + // + const T two_theta = + T(2.0) * ((cos_theta < 0.0) + ? atan2(-sin_theta, -cos_theta) + : atan2(sin_theta, cos_theta)); + const T k = two_theta / sin_theta; angle_axis[0] = q1 * k; angle_axis[1] = q2 * k; angle_axis[2] = q3 * k; @@ -259,7 +272,7 @@ inline void RotationMatrixToAngleAxis(const T * R, T * angle_axis) { // Case 2: theta ~ 0, means sin(theta) ~ theta to a good // approximation. - if (costheta > 0) { + if (costheta > 0.0) { const T kHalf = T(0.5); for (int i = 0; i < 3; ++i) { angle_axis[i] *= kHalf; @@ -284,8 +297,8 @@ inline void RotationMatrixToAngleAxis(const T * R, T * angle_axis) { // angle_axis[i] should be positive, otherwise negative. for (int i = 0; i < 3; ++i) { angle_axis[i] = theta * sqrt((R[i*4] - costheta) * inv_one_minus_costheta); - if (((sintheta < 0) && (angle_axis[i] > 0)) || - ((sintheta > 0) && (angle_axis[i] < 0))) { + if (((sintheta < 0.0) && (angle_axis[i] > 0.0)) || + ((sintheta > 0.0) && (angle_axis[i] < 0.0))) { angle_axis[i] = -angle_axis[i]; } } @@ -334,7 +347,8 @@ template inline void EulerAnglesToRotationMatrix(const T* euler, const int row_stride, T* R) { - const T degrees_to_radians(M_PI / 180.0); + const double kPi = 3.14159265358979323846; + const T degrees_to_radians(kPi / 180.0); const T pitch(euler[0] * degrees_to_radians); const T roll(euler[1] * degrees_to_radians); @@ -517,10 +531,4 @@ void AngleAxisRotatePoint(const T angle_axis[3], const T pt[3], T result[3]) { } // namespace ceres -// Clean define pollution. -#ifdef CERES_NEED_M_PI_UNDEF -#undef CERES_NEED_M_PI_UNDEF -#undef M_PI -#endif - #endif // CERES_PUBLIC_ROTATION_H_ diff --git a/extern/libmv/third_party/ceres/include/ceres/solver.h b/extern/libmv/third_party/ceres/include/ceres/solver.h index bd669272023..31d5e8d7987 100644 --- a/extern/libmv/third_party/ceres/include/ceres/solver.h +++ b/extern/libmv/third_party/ceres/include/ceres/solver.h @@ -34,10 +34,10 @@ #include #include #include - -#include "ceres/iteration_callback.h" +#include "ceres/crs_matrix.h" #include "ceres/internal/macros.h" #include "ceres/internal/port.h" +#include "ceres/iteration_callback.h" #include "ceres/types.h" namespace ceres { @@ -57,24 +57,47 @@ class Solver { struct Options { // Default constructor that sets up a generic sparse problem. Options() { - minimizer_type = LEVENBERG_MARQUARDT; + trust_region_strategy_type = LEVENBERG_MARQUARDT; + dogleg_type = TRADITIONAL_DOGLEG; + use_nonmonotonic_steps = false; + max_consecutive_nonmonotonic_steps = 5; max_num_iterations = 50; - max_solver_time_sec = 1.0e9; + max_solver_time_in_seconds = 1e9; num_threads = 1; - tau = 1e-4; + initial_trust_region_radius = 1e4; + max_trust_region_radius = 1e16; + min_trust_region_radius = 1e-32; min_relative_decrease = 1e-3; + lm_min_diagonal = 1e-6; + lm_max_diagonal = 1e32; + max_num_consecutive_invalid_steps = 5; function_tolerance = 1e-6; gradient_tolerance = 1e-10; parameter_tolerance = 1e-8; -#ifndef CERES_NO_SUITESPARSE - linear_solver_type = SPARSE_NORMAL_CHOLESKY; -#else + +#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE) linear_solver_type = DENSE_QR; -#endif // CERES_NO_SUITESPARSE +#else + linear_solver_type = SPARSE_NORMAL_CHOLESKY; +#endif + preconditioner_type = JACOBI; + + sparse_linear_algebra_library = SUITE_SPARSE; +#if defined(CERES_NO_SUITESPARSE) && !defined(CERES_NO_CXSPARSE) + sparse_linear_algebra_library = CX_SPARSE; +#endif + num_linear_solver_threads = 1; num_eliminate_blocks = 0; ordering_type = NATURAL; + +#if defined(CERES_NO_SUITESPARSE) + use_block_amd = false; +#else + use_block_amd = true; +#endif + linear_solver_min_num_iterations = 1; linear_solver_max_num_iterations = 500; eta = 1e-1; @@ -82,10 +105,13 @@ class Solver { logging_type = PER_MINIMIZER_ITERATION; minimizer_progress_to_stdout = false; return_initial_residuals = false; + return_initial_gradient = false; + return_initial_jacobian = false; return_final_residuals = false; + return_final_gradient = false; + return_final_jacobian = false; lsqp_dump_directory = "/tmp"; lsqp_dump_format_type = TEXTFILE; - crash_and_dump_lsqp_on_failure = false; check_gradients = false; gradient_check_relative_precision = 1e-8; numeric_derivative_relative_step_size = 1e-6; @@ -94,27 +120,78 @@ class Solver { // Minimizer options ---------------------------------------- - MinimizerType minimizer_type; + TrustRegionStrategyType trust_region_strategy_type; + + // Type of dogleg strategy to use. + DoglegType dogleg_type; + + // The classical trust region methods are descent methods, in that + // they only accept a point if it strictly reduces the value of + // the objective function. + // + // Relaxing this requirement allows the algorithm to be more + // efficient in the long term at the cost of some local increase + // in the value of the objective function. + // + // This is because allowing for non-decreasing objective function + // values in a princpled manner allows the algorithm to "jump over + // boulders" as the method is not restricted to move into narrow + // valleys while preserving its convergence properties. + // + // Setting use_nonmonotonic_steps to true enables the + // non-monotonic trust region algorithm as described by Conn, + // Gould & Toint in "Trust Region Methods", Section 10.1. + // + // The parameter max_consecutive_nonmonotonic_steps controls the + // window size used by the step selection algorithm to accept + // non-monotonic steps. + // + // Even though the value of the objective function may be larger + // than the minimum value encountered over the course of the + // optimization, the final parameters returned to the user are the + // ones corresponding to the minimum cost over all iterations. + bool use_nonmonotonic_steps; + int max_consecutive_nonmonotonic_steps; // Maximum number of iterations for the minimizer to run for. int max_num_iterations; // Maximum time for which the minimizer should run for. - double max_solver_time_sec; + double max_solver_time_in_seconds; // Number of threads used by Ceres for evaluating the cost and // jacobians. int num_threads; - // For Levenberg-Marquardt, the initial value for the - // regularizer. This is the inversely related to the size of the - // initial trust region. - double tau; + // Trust region minimizer settings. + double initial_trust_region_radius; + double max_trust_region_radius; + + // Minimizer terminates when the trust region radius becomes + // smaller than this value. + double min_trust_region_radius; - // For trust region methods, this is lower threshold for the - // relative decrease before a step is accepted. + // Lower bound for the relative decrease before a step is + // accepted. double min_relative_decrease; + // For the Levenberg-Marquadt algorithm, the scaled diagonal of + // the normal equations J'J is used to control the size of the + // trust region. Extremely small and large values along the + // diagonal can make this regularization scheme + // fail. lm_max_diagonal and lm_min_diagonal, clamp the values of + // diag(J'J) from above and below. In the normal course of + // operation, the user should not have to modify these parameters. + double lm_min_diagonal; + double lm_max_diagonal; + + // Sometimes due to numerical conditioning problems or linear + // solver flakiness, the trust region strategy may return a + // numerically invalid step that can be fixed by reducing the + // trust region size. So the TrustRegionMinimizer allows for a few + // successive invalid steps before it declares NUMERICAL_FAILURE. + int max_num_consecutive_invalid_steps; + // Minimizer terminates when // // (new_cost - old_cost) < function_tolerance * old_cost; @@ -141,6 +218,12 @@ class Solver { // Type of preconditioner to use with the iterative linear solvers. PreconditionerType preconditioner_type; + // Ceres supports using multiple sparse linear algebra libraries + // for sparse matrix ordering and factorizations. Currently, + // SUITE_SPARSE and CX_SPARSE are the valid choices, depending on + // whether they are linked into Ceres at build time. + SparseLinearAlgebraLibraryType sparse_linear_algebra_library; + // Number of threads used by Ceres to solve the Newton // step. Currently only the SPARSE_SCHUR solver is capable of // using this setting. @@ -170,6 +253,19 @@ class Solver { // non-empty. vector ordering; + // By virtue of the modeling layer in Ceres being block oriented, + // all the matrices used by Ceres are also block oriented. When + // doing sparse direct factorization of these matrices (for + // SPARSE_NORMAL_CHOLESKY, SPARSE_SCHUR and ITERATIVE in + // conjunction with CLUSTER_TRIDIAGONAL AND CLUSTER_JACOBI + // preconditioners), the fill-reducing ordering algorithms can + // either be run on the block or the scalar form of these matrices. + // Running it on the block form exposes more of the super-nodal + // structure of the matrix to the factorization routines. Setting + // this parameter to true runs the ordering algorithms in block + // form. Currently this option only makes sense with + // sparse_linear_algebra_library = SUITE_SPARSE. + bool use_block_amd; // Minimum number of iterations for which the linear solver should // run, even if the convergence criterion is satisfied. @@ -206,7 +302,12 @@ class Solver { bool minimizer_progress_to_stdout; bool return_initial_residuals; + bool return_initial_gradient; + bool return_initial_jacobian; + bool return_final_residuals; + bool return_final_gradient; + bool return_final_jacobian; // List of iterations at which the optimizer should dump the // linear least squares problem to disk. Useful for testing and @@ -217,15 +318,6 @@ class Solver { string lsqp_dump_directory; DumpFormatType lsqp_dump_format_type; - // Dump the linear least squares problem to disk if the minimizer - // fails due to NUMERICAL_FAILURE and crash the process. This flag - // is useful for generating debugging information. The problem is - // dumped in a file whose name is determined by - // Solver::Options::lsqp_dump_format. - // - // Note: This requires a version of Ceres built with protocol buffers. - bool crash_and_dump_lsqp_on_failure; - // Finite differences options ---------------------------------------------- // Check all jacobians computed by each residual block with finite @@ -273,16 +365,25 @@ class Solver { bool update_state_every_iteration; // Callbacks that are executed at the end of each iteration of the - // Minimizer. They are executed in the order that they are - // specified in this vector. By default, parameter blocks are - // updated only at the end of the optimization, i.e when the - // Minimizer terminates. This behaviour is controlled by + // Minimizer. An iteration may terminate midway, either due to + // numerical failures or because one of the convergence tests has + // been satisfied. In this case none of the callbacks are + // executed. + + // Callbacks are executed in the order that they are specified in + // this vector. By default, parameter blocks are updated only at + // the end of the optimization, i.e when the Minimizer + // terminates. This behaviour is controlled by // update_state_every_variable. If the user wishes to have access // to the update parameter blocks when his/her callbacks are // executed, then set update_state_every_iteration to true. // // The solver does NOT take ownership of these pointers. vector callbacks; + + // If non-empty, a summary of the execution of the solver is + // recorded to this file. + string solver_log; }; struct Summary { @@ -313,20 +414,74 @@ class Solver { // blocks that they depend on were fixed. double fixed_cost; - // Residuals before and after the optimization. Each vector - // contains problem.NumResiduals() elements. Residuals are in the - // same order in which they were added to the problem object when - // constructing this problem. + // Vectors of residuals before and after the optimization. The + // entries of these vectors are in the order in which + // ResidualBlocks were added to the Problem object. + // + // Whether the residual vectors are populated with values is + // controlled by Solver::Options::return_initial_residuals and + // Solver::Options::return_final_residuals respectively. vector initial_residuals; vector final_residuals; + // Gradient vectors, before and after the optimization. The rows + // are in the same order in which the ParameterBlocks were added + // to the Problem object. + // + // NOTE: Since AddResidualBlock adds ParameterBlocks to the + // Problem automatically if they do not already exist, if you wish + // to have explicit control over the ordering of the vectors, then + // use Problem::AddParameterBlock to explicitly add the + // ParameterBlocks in the order desired. + // + // Whether the vectors are populated with values is controlled by + // Solver::Options::return_initial_gradient and + // Solver::Options::return_final_gradient respectively. + vector initial_gradient; + vector final_gradient; + + // Jacobian matrices before and after the optimization. The rows + // of these matrices are in the same order in which the + // ResidualBlocks were added to the Problem object. The columns + // are in the same order in which the ParameterBlocks were added + // to the Problem object. + // + // NOTE: Since AddResidualBlock adds ParameterBlocks to the + // Problem automatically if they do not already exist, if you wish + // to have explicit control over the column ordering of the + // matrix, then use Problem::AddParameterBlock to explicitly add + // the ParameterBlocks in the order desired. + // + // The Jacobian matrices are stored as compressed row sparse + // matrices. Please see ceres/crs_matrix.h for more details of the + // format. + // + // Whether the Jacboan matrices are populated with values is + // controlled by Solver::Options::return_initial_jacobian and + // Solver::Options::return_final_jacobian respectively. + CRSMatrix initial_jacobian; + CRSMatrix final_jacobian; + vector iterations; int num_successful_steps; int num_unsuccessful_steps; + // When the user calls Solve, before the actual optimization + // occurs, Ceres performs a number of preprocessing steps. These + // include error checks, memory allocations, and reorderings. This + // time is accounted for as preprocessing time. double preprocessor_time_in_seconds; + + // Time spent in the TrustRegionMinimizer. double minimizer_time_in_seconds; + + // After the Minimizer is finished, some time is spent in + // re-evaluating residuals etc. This time is accounted for in the + // postprocessor time. + double postprocessor_time_in_seconds; + + // Some total of all time spent inside Ceres when Solve is called. double total_time_in_seconds; // Preprocessor summary. @@ -354,6 +509,10 @@ class Solver { PreconditionerType preconditioner_type; OrderingType ordering_type; + + TrustRegionStrategyType trust_region_strategy_type; + DoglegType dogleg_type; + SparseLinearAlgebraLibraryType sparse_linear_algebra_library; }; // Once a least squares problem has been built, this function takes diff --git a/extern/libmv/third_party/ceres/include/ceres/types.h b/extern/libmv/third_party/ceres/include/ceres/types.h index a30c79029ac..3980885b53c 100644 --- a/extern/libmv/third_party/ceres/include/ceres/types.h +++ b/extern/libmv/third_party/ceres/include/ceres/types.h @@ -59,14 +59,18 @@ enum LinearSolverType { // normal equations A'A x = A'b. They are direct solvers and do not // assume any special problem structure. - // Solve the normal equations using a sparse cholesky solver; based - // on CHOLMOD. - SPARSE_NORMAL_CHOLESKY, + // Solve the normal equations using a dense Cholesky solver; based + // on Eigen. + DENSE_NORMAL_CHOLESKY, // Solve the normal equations using a dense QR solver; based on // Eigen. DENSE_QR, + // Solve the normal equations using a sparse cholesky solver; requires + // SuiteSparse or CXSparse. + SPARSE_NORMAL_CHOLESKY, + // Specialized solvers, specific to problems with a generalized // bi-partitite structure. @@ -110,6 +114,15 @@ enum PreconditionerType { CLUSTER_TRIDIAGONAL }; +enum SparseLinearAlgebraLibraryType { + // High performance sparse Cholesky factorization and approximate + // minimum degree ordering. + SUITE_SPARSE, + + // A lightweight replacment for SuiteSparse. + CX_SPARSE +}; + enum LinearSolverTerminationType { // Termination criterion was met. For factorization based solvers // the tolerance is assumed to be zero. Any user provided values are @@ -149,8 +162,47 @@ enum LoggingType { PER_MINIMIZER_ITERATION }; -enum MinimizerType { - LEVENBERG_MARQUARDT +// Ceres supports different strategies for computing the trust region +// step. +enum TrustRegionStrategyType { + // The default trust region strategy is to use the step computation + // used in the Levenberg-Marquardt algorithm. For more details see + // levenberg_marquardt_strategy.h + LEVENBERG_MARQUARDT, + + // Powell's dogleg algorithm interpolates between the Cauchy point + // and the Gauss-Newton step. It is particularly useful if the + // LEVENBERG_MARQUARDT algorithm is making a large number of + // unsuccessful steps. For more details see dogleg_strategy.h. + // + // NOTES: + // + // 1. This strategy has not been experimented with or tested as + // extensively as LEVENBERG_MARQUARDT, and therefore it should be + // considered EXPERIMENTAL for now. + // + // 2. For now this strategy should only be used with exact + // factorization based linear solvers, i.e., SPARSE_SCHUR, + // DENSE_SCHUR, DENSE_QR and SPARSE_NORMAL_CHOLESKY. + DOGLEG +}; + +// Ceres supports two different dogleg strategies. +// The "traditional" dogleg method by Powell and the +// "subspace" method described in +// R. H. Byrd, R. B. Schnabel, and G. A. Shultz, +// "Approximate solution of the trust region problem by minimization +// over two-dimensional subspaces", Mathematical Programming, +// 40 (1988), pp. 247--263 +enum DoglegType { + // The traditional approach constructs a dogleg path + // consisting of two line segments and finds the furthest + // point on that path that is still inside the trust region. + TRADITIONAL_DOGLEG, + + // The subspace approach finds the exact minimum of the model + // constrained to the subspace spanned by the dogleg path. + SUBSPACE_DOGLEG }; enum SolverTerminationType { @@ -246,11 +298,15 @@ enum DimensionType { const char* LinearSolverTypeToString(LinearSolverType type); const char* PreconditionerTypeToString(PreconditionerType type); +const char* SparseLinearAlgebraLibraryTypeToString( + SparseLinearAlgebraLibraryType type); const char* LinearSolverTerminationTypeToString( LinearSolverTerminationType type); const char* OrderingTypeToString(OrderingType type); const char* SolverTerminationTypeToString(SolverTerminationType type); - +const char* SparseLinearAlgebraLibraryTypeToString( + SparseLinearAlgebraLibraryType type); +const char* TrustRegionStrategyTypeToString( TrustRegionStrategyType type); bool IsSchurType(LinearSolverType type); } // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/array_utils.cc b/extern/libmv/third_party/ceres/internal/ceres/array_utils.cc new file mode 100644 index 00000000000..673baa4f70f --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/array_utils.cc @@ -0,0 +1,67 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#include "ceres/array_utils.h" + +#include +#include +#include "ceres/fpclassify.h" + +namespace ceres { +namespace internal { + +// It is a near impossibility that user code generates this exact +// value in normal operation, thus we will use it to fill arrays +// before passing them to user code. If on return an element of the +// array still contains this value, we will assume that the user code +// did not write to that memory location. +const double kImpossibleValue = 1e302; + +bool IsArrayValid(const int size, const double* x) { + if (x != NULL) { + for (int i = 0; i < size; ++i) { + if (!IsFinite(x[i]) || (x[i] == kImpossibleValue)) { + return false; + } + } + } + return true; +} + +void InvalidateArray(const int size, double* x) { + if (x != NULL) { + for (int i = 0; i < size; ++i) { + x[i] = kImpossibleValue; + } + } +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/array_utils.h b/extern/libmv/third_party/ceres/internal/ceres/array_utils.h new file mode 100644 index 00000000000..99cc8d8ebbf --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/array_utils.h @@ -0,0 +1,65 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) +// +// Utility routines for validating arrays. +// +// These are useful for detecting two common class of errors. +// +// 1. Uninitialized memory - where the user for some reason did not +// compute part of an array, but the code expects it. +// +// 2. Numerical failure while computing the cost/residual/jacobian, +// e.g. NaN, infinities etc. This is particularly useful since the +// automatic differentiation code does computations that are not +// evident to the user and can silently generate hard to debug errors. + +#ifndef CERES_INTERNAL_ARRAY_UTILS_H_ +#define CERES_INTERNAL_ARRAY_UTILS_H_ + +#include "ceres/internal/port.h" + +namespace ceres { +namespace internal { + +// Fill the array x with an impossible value that the user code is +// never expected to compute. +void InvalidateArray(int size, double* x); + +// Check if all the entries of the array x are valid, i.e. all the +// values in the array should be finite and none of them should be +// equal to the "impossible" value used by InvalidateArray. +bool IsArrayValid(int size, const double* x); + +extern const double kImpossibleValue; + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_ARRAY_UTILS_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_evaluate_preparer.cc b/extern/libmv/third_party/ceres/internal/ceres/block_evaluate_preparer.cc index 05e63eb560b..9edc4fa23bd 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/block_evaluate_preparer.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/block_evaluate_preparer.cc @@ -40,16 +40,26 @@ namespace ceres { namespace internal { -void BlockEvaluatePreparer::Init(int** jacobian_layout) { +void BlockEvaluatePreparer::Init(int const* const* jacobian_layout, + int max_derivatives_per_residual_block) { jacobian_layout_ = jacobian_layout; + scratch_evaluate_preparer_.Init(max_derivatives_per_residual_block); } // Point the jacobian blocks directly into the block sparse matrix. void BlockEvaluatePreparer::Prepare(const ResidualBlock* residual_block, int residual_block_index, SparseMatrix* jacobian, - double** jacobians) const { - CHECK(jacobian != NULL); + double** jacobians) { + // If the overall jacobian is not available, use the scratch space. + if (jacobian == NULL) { + scratch_evaluate_preparer_.Prepare(residual_block, + residual_block_index, + jacobian, + jacobians); + return; + } + double* jacobian_values = down_cast(jacobian)->mutable_values(); diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_evaluate_preparer.h b/extern/libmv/third_party/ceres/internal/ceres/block_evaluate_preparer.h index a7869311e6e..354acc031f4 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/block_evaluate_preparer.h +++ b/extern/libmv/third_party/ceres/internal/ceres/block_evaluate_preparer.h @@ -36,6 +36,8 @@ #ifndef CERES_INTERNAL_BLOCK_EVALUATE_PREPARER_H_ #define CERES_INTERNAL_BLOCK_EVALUATE_PREPARER_H_ +#include "ceres/scratch_evaluate_preparer.h" + namespace ceres { namespace internal { @@ -47,18 +49,26 @@ class BlockEvaluatePreparer { // Using Init() instead of a constructor allows for allocating this structure // with new[]. This is because C++ doesn't allow passing arguments to objects // constructed with new[] (as opposed to plain 'new'). - void Init(int** jacobian_layout); + void Init(int const* const* jacobian_layout, + int max_derivatives_per_residual_block); // EvaluatePreparer interface - // Point the jacobian blocks directly into the block sparse matrix. + // Point the jacobian blocks directly into the block sparse matrix, if + // jacobian is non-null. Otherwise, uses an internal per-thread buffer to + // store the jacobians temporarily. void Prepare(const ResidualBlock* residual_block, int residual_block_index, SparseMatrix* jacobian, - double** jacobians) const; + double** jacobians); private: int const* const* jacobian_layout_; + + // For the case that the overall jacobian is not available, but the + // individual jacobians are requested, use a pass-through scratch evaluate + // preparer. + ScratchEvaluatePreparer scratch_evaluate_preparer_; }; } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc b/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc index 1a5001f9c71..474c37f7ca4 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc @@ -40,11 +40,10 @@ namespace ceres { namespace internal { -BlockJacobiPreconditioner::BlockJacobiPreconditioner( - const LinearOperator& A) - : block_structure_( - *(down_cast(&A)->block_structure())), - num_rows_(A.num_rows()) { +BlockJacobiPreconditioner::BlockJacobiPreconditioner(const LinearOperator& A) + : num_rows_(A.num_rows()), + block_structure_( + *(down_cast(&A)->block_structure())) { // Calculate the amount of storage needed. int storage_needed = 0; for (int c = 0; c < block_structure_.cols.size(); ++c) { diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_jacobian_writer.cc b/extern/libmv/third_party/ceres/internal/ceres/block_jacobian_writer.cc index 52a58bb43a6..f90c350cc80 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/block_jacobian_writer.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/block_jacobian_writer.cc @@ -136,9 +136,12 @@ BlockJacobianWriter::BlockJacobianWriter(const Evaluator::Options& options, // makes the final Write() a nop. BlockEvaluatePreparer* BlockJacobianWriter::CreateEvaluatePreparers( int num_threads) { + int max_derivatives_per_residual_block = + program_->MaxDerivativesPerResidualBlock(); + BlockEvaluatePreparer* preparers = new BlockEvaluatePreparer[num_threads]; for (int i = 0; i < num_threads; i++) { - preparers[i].Init(&jacobian_layout_[0]); + preparers[i].Init(&jacobian_layout_[0], max_derivatives_per_residual_block); } return preparers; } diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc index 2afaf5e2ea2..0f95e8932b8 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc @@ -28,10 +28,10 @@ // // Author: sameeragarwal@google.com (Sameer Agarwal) +#include "glog/logging.h" #include "ceres/block_random_access_dense_matrix.h" #include -#include #include "ceres/internal/eigen.h" #include "ceres/internal/scoped_ptr.h" diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.h index 3a0096209f7..9f27a4c30f3 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.h +++ b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.h @@ -89,7 +89,7 @@ class BlockRandomAccessDenseMatrix : public BlockRandomAccessMatrix { vector block_layout_; scoped_array values_; - DISALLOW_COPY_AND_ASSIGN(BlockRandomAccessDenseMatrix); + CERES_DISALLOW_COPY_AND_ASSIGN(BlockRandomAccessDenseMatrix); }; } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_matrix.h index f398af3be87..b76cb78b160 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_matrix.h +++ b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_matrix.h @@ -77,7 +77,7 @@ namespace internal { // // if (cell != NULL) { // MatrixRef m(cell->values, row_stride, col_stride); -// MutexLock l(&cell->m); +// CeresMutexLock l(&cell->m); // m.block(row, col, row_block_size, col_block_size) = ... // } diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc index c496fcd13de..9ed62ce948b 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc @@ -28,17 +28,17 @@ // // Author: sameeragarwal@google.com (Sameer Agarwal) +#include "glog/logging.h" #include "ceres/block_random_access_sparse_matrix.h" #include #include #include #include -#include -#include "ceres/mutex.h" -#include "ceres/triplet_sparse_matrix.h" #include "ceres/internal/port.h" #include "ceres/internal/scoped_ptr.h" +#include "ceres/mutex.h" +#include "ceres/triplet_sparse_matrix.h" #include "ceres/types.h" namespace ceres { diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.h index 12613c3daa0..48a00437cf6 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.h +++ b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.h @@ -38,6 +38,7 @@ #include "ceres/block_random_access_matrix.h" #include "ceres/collections_port.h" #include "ceres/triplet_sparse_matrix.h" +#include "ceres/integral_types.h" #include "ceres/internal/macros.h" #include "ceres/internal/port.h" #include "ceres/internal/scoped_ptr.h" @@ -84,11 +85,11 @@ class BlockRandomAccessSparseMatrix : public BlockRandomAccessMatrix { TripletSparseMatrix* mutable_matrix() { return tsm_.get(); } private: - long int IntPairToLong(int a, int b) { + int64 IntPairToLong(int a, int b) { return a * kMaxRowBlocks + b; } - const int kMaxRowBlocks; + const int64 kMaxRowBlocks; // row/column block sizes. const vector blocks_; @@ -100,7 +101,8 @@ class BlockRandomAccessSparseMatrix : public BlockRandomAccessMatrix { // The underlying matrix object which actually stores the cells. scoped_ptr tsm_; - DISALLOW_COPY_AND_ASSIGN(BlockRandomAccessSparseMatrix); + friend class BlockRandomAccessSparseMatrixTest; + CERES_DISALLOW_COPY_AND_ASSIGN(BlockRandomAccessSparseMatrix); }; } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/block_sparse_matrix.cc index 7dd395e2975..dbe5ec93ef0 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/block_sparse_matrix.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/block_sparse_matrix.cc @@ -33,11 +33,11 @@ #include #include #include -#include #include "ceres/block_structure.h" +#include "ceres/internal/eigen.h" #include "ceres/matrix_proto.h" #include "ceres/triplet_sparse_matrix.h" -#include "ceres/internal/eigen.h" +#include "glog/logging.h" namespace ceres { namespace internal { @@ -81,7 +81,7 @@ BlockSparseMatrix::BlockSparseMatrix( CHECK_NOTNULL(values_.get()); } -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS BlockSparseMatrix::BlockSparseMatrix(const SparseMatrixProto& outer_proto) { CHECK(outer_proto.has_block_matrix()); @@ -244,7 +244,7 @@ const CompressedRowBlockStructure* BlockSparseMatrix::block_structure() return block_structure_.get(); } -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS void BlockSparseMatrix::ToProto(SparseMatrixProto* outer_proto) const { outer_proto->Clear(); diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/block_sparse_matrix.h index f71446e8f58..513d398c54d 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/block_sparse_matrix.h +++ b/extern/libmv/third_party/ceres/internal/ceres/block_sparse_matrix.h @@ -74,7 +74,7 @@ class BlockSparseMatrixBase : public SparseMatrix { virtual const double* RowBlockValues(int row_block_index) const = 0; private: - DISALLOW_COPY_AND_ASSIGN(BlockSparseMatrixBase); + CERES_DISALLOW_COPY_AND_ASSIGN(BlockSparseMatrixBase); }; // This class implements the SparseMatrix interface for storing and @@ -96,7 +96,7 @@ class BlockSparseMatrix : public BlockSparseMatrixBase { explicit BlockSparseMatrix(CompressedRowBlockStructure* block_structure); // Construct a block sparse matrix from a protocol buffer. -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS explicit BlockSparseMatrix(const SparseMatrixProto& proto); #endif @@ -110,7 +110,7 @@ class BlockSparseMatrix : public BlockSparseMatrixBase { virtual void SquaredColumnNorm(double* x) const; virtual void ScaleColumns(const double* scale); virtual void ToDenseMatrix(Matrix* dense_matrix) const; -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS virtual void ToProto(SparseMatrixProto* proto) const; #endif virtual void ToTextFile(FILE* file) const; @@ -135,7 +135,7 @@ class BlockSparseMatrix : public BlockSparseMatrixBase { int num_nonzeros_; scoped_array values_; scoped_ptr block_structure_; - DISALLOW_COPY_AND_ASSIGN(BlockSparseMatrix); + CERES_DISALLOW_COPY_AND_ASSIGN(BlockSparseMatrix); }; } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_structure.cc b/extern/libmv/third_party/ceres/internal/ceres/block_structure.cc index 5add4f3b94d..e61131192af 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/block_structure.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/block_structure.cc @@ -38,7 +38,7 @@ bool CellLessThan(const Cell& lhs, const Cell& rhs) { return (lhs.block_id < rhs.block_id); } -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS void ProtoToBlockStructure(const BlockStructureProto &proto, CompressedRowBlockStructure *block_structure) { // Decode the column blocks. diff --git a/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.cc b/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.cc index 53190ada6fc..d0dc1e670c2 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.cc @@ -31,11 +31,11 @@ #include "ceres/canonical_views_clustering.h" -#include -#include "ceres/graph.h" #include "ceres/collections_port.h" -#include "ceres/map_util.h" +#include "ceres/graph.h" #include "ceres/internal/macros.h" +#include "ceres/map_util.h" +#include "glog/logging.h" namespace ceres { namespace internal { @@ -75,7 +75,7 @@ class CanonicalViewsClustering { IntMap view_to_canonical_view_; // Maps a view to its similarity to its current cluster center. HashMap view_to_canonical_view_similarity_; - DISALLOW_COPY_AND_ASSIGN(CanonicalViewsClustering); + CERES_DISALLOW_COPY_AND_ASSIGN(CanonicalViewsClustering); }; void ComputeCanonicalViewsClustering( diff --git a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h b/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h index dd36f99006b..877b4c4ceea 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h +++ b/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h @@ -57,7 +57,7 @@ class CgnrSolver : public LinearSolver { private: const LinearSolver::Options options_; scoped_ptr jacobi_preconditioner_; - DISALLOW_COPY_AND_ASSIGN(CgnrSolver); + CERES_DISALLOW_COPY_AND_ASSIGN(CgnrSolver); }; } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/collections_port.h b/extern/libmv/third_party/ceres/internal/ceres/collections_port.h index 9dff0efe245..c2fce9033cd 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/collections_port.h +++ b/extern/libmv/third_party/ceres/internal/ceres/collections_port.h @@ -33,31 +33,49 @@ #ifndef CERES_INTERNAL_COLLECTIONS_PORT_H_ #define CERES_INTERNAL_COLLECTIONS_PORT_H_ -#ifdef CERES_HASH_BOOST -#include -#include +#if defined(CERES_NO_TR1) +# include +# include #else -#if defined(_MSC_VER) && _MSC_VER <= 1700 -#include -#include -#else -#include -#include -#endif +# if defined(_MSC_VER) && _MSC_VER <= 1600 +# include +# include +# else +# include +# include +# endif #endif - #include #include "ceres/integral_types.h" #include "ceres/internal/port.h" +// Some systems don't have access to TR1. In that case, substitute the hash +// map/set with normal map/set. The price to pay is slightly slower speed for +// some operations. +#if defined(CERES_NO_TR1) + namespace ceres { namespace internal { template -struct HashMap : tr1::unordered_map {}; +struct HashMap : map {}; template -struct HashSet : tr1::unordered_set {}; +struct HashSet : set {}; + +} // namespace internal +} // namespace ceres + +#else + +namespace ceres { +namespace internal { + +template +struct HashMap : std::tr1::unordered_map {}; + +template +struct HashSet : std::tr1::unordered_set {}; #if defined(_WIN32) && !defined(__MINGW64__) && !defined(__MINGW32__) #define GG_LONGLONG(x) x##I64 @@ -124,11 +142,7 @@ CERES_HASH_NAMESPACE_START // Hasher for STL pairs. Requires hashers for both members to be defined. template -#ifdef CERES_HASH_BOOST -struct hash { -#else struct hash > { -#endif size_t operator()(const pair& p) const { size_t h1 = hash()(p.first); size_t h2 = hash()(p.second); @@ -148,4 +162,6 @@ struct hash > { CERES_HASH_NAMESPACE_END +#endif // CERES_NO_TR1 + #endif // CERES_INTERNAL_COLLECTIONS_PORT_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc index aa883b7d353..912c4845441 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc @@ -130,8 +130,24 @@ SparseMatrix* CompressedRowJacobianWriter::CreateJacobian() const { } row_pos += num_residuals; } - CHECK_EQ(num_jacobian_nonzeros, rows[total_num_residuals]); + + // Populate the row and column block vectors for use by block + // oriented ordering algorithms. This is useful when + // Solver::Options::use_block_amd = true. + const vector& parameter_blocks = program_->parameter_blocks(); + vector& col_blocks = *(jacobian->mutable_col_blocks()); + col_blocks.resize(parameter_blocks.size()); + for (int i = 0; i < parameter_blocks.size(); ++i) { + col_blocks[i] = parameter_blocks[i]->LocalSize(); + } + + vector& row_blocks = *(jacobian->mutable_row_blocks()); + row_blocks.resize(residual_blocks.size()); + for (int i = 0; i < residual_blocks.size(); ++i) { + row_blocks[i] = residual_blocks[i]->NumResiduals(); + } + return jacobian; } diff --git a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.cc index 95edf5396af..1b61468aaae 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.cc @@ -32,15 +32,22 @@ #include #include -#include "ceres/matrix_proto.h" +#include "ceres/crs_matrix.h" #include "ceres/internal/port.h" +#include "ceres/matrix_proto.h" namespace ceres { namespace internal { namespace { // Helper functor used by the constructor for reordering the contents -// of a TripletSparseMatrix. +// of a TripletSparseMatrix. This comparator assumes thay there are no +// duplicates in the pair of arrays rows and cols, i.e., there is no +// indices i and j (not equal to each other) s.t. +// +// rows[i] == rows[j] && cols[i] == cols[j] +// +// If this is the case, this functor will not be a StrictWeakOrdering. struct RowColLessThan { RowColLessThan(const int* rows, const int* cols) : rows(rows), cols(cols) { @@ -128,7 +135,7 @@ CompressedRowSparseMatrix::CompressedRowSparseMatrix( CHECK_EQ(num_nonzeros(), m.num_nonzeros()); } -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS CompressedRowSparseMatrix::CompressedRowSparseMatrix( const SparseMatrixProto& outer_proto) { CHECK(outer_proto.has_compressed_row_matrix()); @@ -241,7 +248,7 @@ void CompressedRowSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const { } } -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS void CompressedRowSparseMatrix::ToProto(SparseMatrixProto* outer_proto) const { CHECK_NOTNULL(outer_proto); @@ -330,5 +337,18 @@ void CompressedRowSparseMatrix::ToTextFile(FILE* file) const { } } +void CompressedRowSparseMatrix::ToCRSMatrix(CRSMatrix* matrix) const { + matrix->num_rows = num_rows(); + matrix->num_cols = num_cols(); + + matrix->rows.resize(matrix->num_rows + 1); + matrix->cols.resize(num_nonzeros()); + matrix->values.resize(num_nonzeros()); + + copy(rows_.get(), rows_.get() + matrix->num_rows + 1, matrix->rows.begin()); + copy(cols_.get(), cols_.get() + num_nonzeros(), matrix->cols.begin()); + copy(values_.get(), values_.get() + num_nonzeros(), matrix->values.begin()); +} + } // namespace internal } // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h index 9a39d28e111..6a9d82842e5 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h +++ b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h @@ -31,14 +31,19 @@ #ifndef CERES_INTERNAL_COMPRESSED_ROW_SPARSE_MATRIX_H_ #define CERES_INTERNAL_COMPRESSED_ROW_SPARSE_MATRIX_H_ +#include #include #include "ceres/sparse_matrix.h" #include "ceres/triplet_sparse_matrix.h" #include "ceres/internal/eigen.h" #include "ceres/internal/macros.h" +#include "ceres/internal/port.h" #include "ceres/types.h" namespace ceres { + +class CRSMatrix; + namespace internal { class SparseMatrixProto; @@ -52,7 +57,7 @@ class CompressedRowSparseMatrix : public SparseMatrix { // // We assume that m does not have any repeated entries. explicit CompressedRowSparseMatrix(const TripletSparseMatrix& m); -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS explicit CompressedRowSparseMatrix(const SparseMatrixProto& proto); #endif @@ -85,7 +90,7 @@ class CompressedRowSparseMatrix : public SparseMatrix { virtual void ScaleColumns(const double* scale); virtual void ToDenseMatrix(Matrix* dense_matrix) const; -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS virtual void ToProto(SparseMatrixProto* proto) const; #endif virtual void ToTextFile(FILE* file) const; @@ -103,6 +108,8 @@ class CompressedRowSparseMatrix : public SparseMatrix { // have the same number of columns as this matrix. void AppendRows(const CompressedRowSparseMatrix& m); + void ToCRSMatrix(CRSMatrix* matrix) const; + // Low level access methods that expose the structure of the matrix. const int* cols() const { return cols_.get(); } int* mutable_cols() { return cols_.get(); } @@ -110,6 +117,12 @@ class CompressedRowSparseMatrix : public SparseMatrix { const int* rows() const { return rows_.get(); } int* mutable_rows() { return rows_.get(); } + const vector& row_blocks() const { return row_blocks_; } + vector* mutable_row_blocks() { return &row_blocks_; } + + const vector& col_blocks() const { return col_blocks_; } + vector* mutable_col_blocks() { return &col_blocks_; } + private: scoped_array cols_; scoped_array rows_; @@ -117,10 +130,17 @@ class CompressedRowSparseMatrix : public SparseMatrix { int num_rows_; int num_cols_; - int max_num_nonzeros_; - DISALLOW_COPY_AND_ASSIGN(CompressedRowSparseMatrix); + // If the matrix has an underlying block structure, then it can also + // carry with it row and column block sizes. This is auxilliary and + // optional information for use by algorithms operating on the + // matrix. The class itself does not make use of this information in + // any way. + vector row_blocks_; + vector col_blocks_; + + CERES_DISALLOW_COPY_AND_ASSIGN(CompressedRowSparseMatrix); }; } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/conditioned_cost_function.cc b/extern/libmv/third_party/ceres/internal/ceres/conditioned_cost_function.cc index ca80bfb9c9d..7322790f717 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/conditioned_cost_function.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/conditioned_cost_function.cc @@ -34,10 +34,10 @@ #include -#include -#include "ceres/stl_util.h" #include "ceres/internal/eigen.h" +#include "ceres/stl_util.h" #include "ceres/types.h" +#include "glog/logging.h" namespace ceres { diff --git a/extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.cc index 75f9e043fa5..ae8e8774709 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.cc @@ -41,18 +41,18 @@ #include #include -#include -#include "ceres/linear_operator.h" +#include "ceres/fpclassify.h" #include "ceres/internal/eigen.h" +#include "ceres/linear_operator.h" #include "ceres/types.h" -#include "ceres/jet.h" +#include "glog/logging.h" namespace ceres { namespace internal { namespace { bool IsZeroOrInfinity(double x) { - return ((x == 0.0) || (isinf(x))); + return ((x == 0.0) || (IsInfinite(x))); } // Constant used in the MATLAB implementation ~ 2 * eps. @@ -115,7 +115,7 @@ LinearSolver::Summary ConjugateGradientsSolver::Solve( for (summary.num_iterations = 1; summary.num_iterations < options_.max_num_iterations; ++summary.num_iterations) { - VLOG(2) << "cg iteration " << summary.num_iterations; + VLOG(3) << "cg iteration " << summary.num_iterations; // Apply preconditioner if (per_solve_options.preconditioner != NULL) { @@ -151,14 +151,14 @@ LinearSolver::Summary ConjugateGradientsSolver::Solve( A->RightMultiply(p.data(), q.data()); double pq = p.dot(q); - if ((pq <= 0) || isinf(pq)) { + if ((pq <= 0) || IsInfinite(pq)) { LOG(ERROR) << "Numerical failure. pq = " << pq; summary.termination_type = FAILURE; break; } double alpha = rho / pq; - if (isinf(alpha)) { + if (IsInfinite(alpha)) { LOG(ERROR) << "Numerical failure. alpha " << alpha; summary.termination_type = FAILURE; break; @@ -202,13 +202,13 @@ LinearSolver::Summary ConjugateGradientsSolver::Solve( // 1. Stephen G. Nash & Ariela Sofer, Assessing A Search // Direction Within A Truncated Newton Method, Operation // Research Letters 9(1990) 219-221. - // + // // 2. Stephen G. Nash, A Survey of Truncated Newton Methods, // Journal of Computational and Applied Mathematics, // 124(1-2), 45-59, 2000. // double zeta = summary.num_iterations * (Q1 - Q0) / Q1; - VLOG(2) << "Q termination: zeta " << zeta + VLOG(3) << "Q termination: zeta " << zeta << " " << per_solve_options.q_tolerance; if (zeta < per_solve_options.q_tolerance) { summary.termination_type = TOLERANCE; @@ -218,7 +218,7 @@ LinearSolver::Summary ConjugateGradientsSolver::Solve( // Residual based termination. norm_r = r. norm(); - VLOG(2) << "R termination: norm_r " << norm_r + VLOG(3) << "R termination: norm_r " << norm_r << " " << tol_r; if (norm_r <= tol_r) { summary.termination_type = TOLERANCE; diff --git a/extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.h b/extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.h index 57f99e31db7..b8dfa56b526 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.h +++ b/extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.h @@ -65,7 +65,7 @@ class ConjugateGradientsSolver : public LinearSolver { private: const LinearSolver::Options options_; - DISALLOW_COPY_AND_ASSIGN(ConjugateGradientsSolver); + CERES_DISALLOW_COPY_AND_ASSIGN(ConjugateGradientsSolver); }; } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/corrector.cc b/extern/libmv/third_party/ceres/internal/ceres/corrector.cc index 4ca2c6f6c86..eff4dff8566 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/corrector.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/corrector.cc @@ -32,8 +32,8 @@ #include #include -#include #include "ceres/internal/eigen.h" +#include "glog/logging.h" namespace ceres { namespace internal { diff --git a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc new file mode 100644 index 00000000000..ca36ce07614 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc @@ -0,0 +1,130 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: strandmark@google.com (Petter Strandmark) + +#ifndef CERES_NO_CXSPARSE + +#include "ceres/cxsparse.h" + +#include "ceres/compressed_row_sparse_matrix.h" +#include "ceres/triplet_sparse_matrix.h" +#include "glog/logging.h" + +namespace ceres { +namespace internal { + +CXSparse::CXSparse() : scratch_size_(0), scratch_(NULL) { +} + +CXSparse::~CXSparse() { + if (scratch_size_ > 0) { + cs_free(scratch_); + } +} + +bool CXSparse::SolveCholesky(cs_di* A, + cs_dis* symbolic_factorization, + double* b) { + // Make sure we have enough scratch space available. + if (scratch_size_ < A->n) { + if (scratch_size_ > 0) { + cs_free(scratch_); + } + scratch_ = reinterpret_cast(cs_malloc(A->n, sizeof(CS_ENTRY))); + } + + // Solve using Cholesky factorization + csn* numeric_factorization = cs_chol(A, symbolic_factorization); + if (numeric_factorization == NULL) { + LOG(WARNING) << "Cholesky factorization failed."; + return false; + } + + // When the Cholesky factorization succeeded, these methods are guaranteed to + // succeeded as well. In the comments below, "x" refers to the scratch space. + // + // Set x = P * b. + cs_ipvec(symbolic_factorization->pinv, b, scratch_, A->n); + + // Set x = L \ x. + cs_lsolve(numeric_factorization->L, scratch_); + + // Set x = L' \ x. + cs_ltsolve(numeric_factorization->L, scratch_); + + // Set b = P' * x. + cs_pvec(symbolic_factorization->pinv, scratch_, b, A->n); + + // Free Cholesky factorization. + cs_nfree(numeric_factorization); + return true; +} + +cs_dis* CXSparse::AnalyzeCholesky(cs_di* A) { + // order = 1 for Cholesky factorization. + return cs_schol(1, A); +} + +cs_di CXSparse::CreateSparseMatrixTransposeView(CompressedRowSparseMatrix* A) { + cs_di At; + At.m = A->num_cols(); + At.n = A->num_rows(); + At.nz = -1; + At.nzmax = A->num_nonzeros(); + At.p = A->mutable_rows(); + At.i = A->mutable_cols(); + At.x = A->mutable_values(); + return At; +} + +cs_di* CXSparse::CreateSparseMatrix(TripletSparseMatrix* tsm) { + cs_di_sparse tsm_wrapper; + tsm_wrapper.nzmax = tsm->num_nonzeros();; + tsm_wrapper.nz = tsm->num_nonzeros();; + tsm_wrapper.m = tsm->num_rows(); + tsm_wrapper.n = tsm->num_cols(); + tsm_wrapper.p = tsm->mutable_cols(); + tsm_wrapper.i = tsm->mutable_rows(); + tsm_wrapper.x = tsm->mutable_values(); + + return cs_compress(&tsm_wrapper); +} + +void CXSparse::Free(cs_di* factor) { + cs_free(factor); +} + +void CXSparse::Free(cs_dis* factor) { + cs_sfree(factor); +} + +} // namespace internal +} // namespace ceres + +#endif // CERES_NO_CXSPARSE diff --git a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h new file mode 100644 index 00000000000..d3b64fcd1a5 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h @@ -0,0 +1,90 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: strandmark@google.com (Petter Strandmark) + +#ifndef CERES_INTERNAL_CXSPARSE_H_ +#define CERES_INTERNAL_CXSPARSE_H_ + +#ifndef CERES_NO_CXSPARSE + +#include "cs.h" + +namespace ceres { +namespace internal { + +class CompressedRowSparseMatrix; +class TripletSparseMatrix; + +// This object provides access to solving linear systems using Cholesky +// factorization with a known symbolic factorization. This features does not +// explicity exist in CXSparse. The methods in the class are nonstatic because +// the class manages internal scratch space. +class CXSparse { + public: + CXSparse(); + ~CXSparse(); + + // Solves a symmetric linear system A * x = b using Cholesky factorization. + // A - The system matrix. + // symbolic_factorization - The symbolic factorization of A. This is obtained + // from AnalyzeCholesky. + // b - The right hand size of the linear equation. This + // array will also recieve the solution. + // Returns false if Cholesky factorization of A fails. + bool SolveCholesky(cs_di* A, cs_dis* symbolic_factorization, double* b); + + // Creates a sparse matrix from a compressed-column form. No memory is + // allocated or copied; the structure A is filled out with info from the + // argument. + cs_di CreateSparseMatrixTransposeView(CompressedRowSparseMatrix* A); + + // Creates a new matrix from a triplet form. Deallocate the returned matrix + // with Free. May return NULL if the compression or allocation fails. + cs_di* CreateSparseMatrix(TripletSparseMatrix* A); + + // Computes a symbolic factorization of A that can be used in SolveCholesky. + // The returned matrix should be deallocated with Free when not used anymore. + cs_dis* AnalyzeCholesky(cs_di* A); + + // Deallocates the memory of a matrix obtained from AnalyzeCholesky. + void Free(cs_di* factor); + void Free(cs_dis* factor); + + private: + // Cached scratch space + CS_ENTRY* scratch_; + int scratch_size_; +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_NO_CXSPARSE + +#endif // CERES_INTERNAL_CXSPARSE_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc new file mode 100644 index 00000000000..f6bb99abf63 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc @@ -0,0 +1,86 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#include "ceres/dense_normal_cholesky_solver.h" + +#include + +#include "Eigen/Dense" +#include "ceres/dense_sparse_matrix.h" +#include "ceres/linear_solver.h" +#include "ceres/internal/eigen.h" +#include "ceres/internal/scoped_ptr.h" +#include "ceres/types.h" + +namespace ceres { +namespace internal { + +DenseNormalCholeskySolver::DenseNormalCholeskySolver( + const LinearSolver::Options& options) + : options_(options) {} + +LinearSolver::Summary DenseNormalCholeskySolver::SolveImpl( + DenseSparseMatrix* A, + const double* b, + const LinearSolver::PerSolveOptions& per_solve_options, + double* x) { + const int num_rows = A->num_rows(); + const int num_cols = A->num_cols(); + + ConstAlignedMatrixRef Aref = A->matrix(); + Matrix lhs(num_cols, num_cols); + lhs.setZero(); + + // lhs += A'A + // + // Using rankUpdate instead of GEMM, exposes the fact that its the + // same matrix being multiplied with itself and that the product is + // symmetric. + lhs.selfadjointView().rankUpdate(Aref.transpose()); + + // rhs = A'b + Vector rhs = Aref.transpose() * ConstVectorRef(b, num_rows); + + if (per_solve_options.D != NULL) { + ConstVectorRef D(per_solve_options.D, num_cols); + lhs += D.array().square().matrix().asDiagonal(); + } + + VectorRef(x, num_cols) = + lhs.selfadjointView().ldlt().solve(rhs); + + LinearSolver::Summary summary; + summary.num_iterations = 1; + summary.termination_type = TOLERANCE; + return summary; +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.h b/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.h new file mode 100644 index 00000000000..de47740583d --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.h @@ -0,0 +1,95 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) +// +// Solve dense rectangular systems Ax = b by forming the normal +// equations and solving them using the Cholesky factorization. + +#ifndef CERES_INTERNAL_DENSE_NORMAL_CHOLESKY_SOLVER_H_ +#define CERES_INTERNAL_DENSE_NORMAL_CHOLESKY_SOLVER_H_ + +#include "ceres/linear_solver.h" +#include "ceres/internal/macros.h" + +namespace ceres { +namespace internal { + +class DenseSparseMatrix; + +// This class implements the LinearSolver interface for solving +// rectangular/unsymmetric (well constrained) linear systems of the +// form +// +// Ax = b +// +// Since there does not usually exist a solution that satisfies these +// equations, the solver instead solves the linear least squares +// problem +// +// min_x |Ax - b|^2 +// +// Setting the gradient of the above optimization problem to zero +// gives us the normal equations +// +// A'Ax = A'b +// +// A'A is a positive definite matrix (hopefully), and the resulting +// linear system can be solved using Cholesky factorization. +// +// If the PerSolveOptions struct has a non-null array D, then the +// augmented/regularized linear system +// +// [ A ]x = [b] +// [ diag(D) ] [0] +// +// is solved. +// +// This class uses the LDLT factorization routines from the Eigen +// library. This solver always returns a solution, it is the user's +// responsibility to judge if the solution is good enough for their +// purposes. +class DenseNormalCholeskySolver: public DenseSparseMatrixSolver { + public: + explicit DenseNormalCholeskySolver(const LinearSolver::Options& options); + + private: + virtual LinearSolver::Summary SolveImpl( + DenseSparseMatrix* A, + const double* b, + const LinearSolver::PerSolveOptions& per_solve_options, + double* x); + + const LinearSolver::Options options_; + CERES_DISALLOW_COPY_AND_ASSIGN(DenseNormalCholeskySolver); +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_DENSE_NORMAL_CHOLESKY_SOLVER_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc index 328505404d7..2b329ee0e9c 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc @@ -33,8 +33,8 @@ #include #include "Eigen/Dense" +#include "ceres/dense_sparse_matrix.h" #include "ceres/linear_solver.h" -#include "ceres/triplet_sparse_matrix.h" #include "ceres/internal/eigen.h" #include "ceres/internal/scoped_ptr.h" #include "ceres/types.h" @@ -62,7 +62,7 @@ LinearSolver::Summary DenseQRSolver::SolveImpl( } // rhs = [b;0] to account for the additional rows in the lhs. - Vector rhs(num_rows + ((per_solve_options.D !=NULL) ? num_cols : 0)); + Vector rhs(num_rows + ((per_solve_options.D != NULL) ? num_cols : 0)); rhs.setZero(); rhs.head(num_rows) = ConstVectorRef(b, num_rows); diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h b/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h index 990c8d445eb..dd683a8c4ea 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h +++ b/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h @@ -28,7 +28,7 @@ // // Author: sameeragarwal@google.com (Sameer Agarwal) // -// Solve dense rectangular systems Ax = b using the QR factoriztion. +// Solve dense rectangular systems Ax = b using the QR factorization. #ifndef CERES_INTERNAL_DENSE_QR_SOLVER_H_ #define CERES_INTERNAL_DENSE_QR_SOLVER_H_ @@ -90,7 +90,7 @@ class DenseQRSolver: public DenseSparseMatrixSolver { double* x); const LinearSolver::Options options_; - DISALLOW_COPY_AND_ASSIGN(DenseQRSolver); + CERES_DISALLOW_COPY_AND_ASSIGN(DenseQRSolver); }; } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc index 5d392ba6c3b..86730cc101b 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc @@ -67,7 +67,7 @@ DenseSparseMatrix::DenseSparseMatrix(const Matrix& m) has_diagonal_reserved_(false) { } -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS DenseSparseMatrix::DenseSparseMatrix(const SparseMatrixProto& outer_proto) : m_(Eigen::MatrixXd::Zero( outer_proto.dense_matrix().num_rows(), @@ -108,7 +108,7 @@ void DenseSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const { *dense_matrix = m_; } -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS void DenseSparseMatrix::ToProto(SparseMatrixProto* outer_proto) const { CHECK(!has_diagonal_appended_) << "Not supported."; outer_proto->Clear(); @@ -183,7 +183,7 @@ void DenseSparseMatrix::ToTextFile(FILE* file) const { CHECK_NOTNULL(file); const int active_rows = (has_diagonal_reserved_ && !has_diagonal_appended_) - ? (m_.rows() - m_.cols()) + ? (m_.rows() - m_.cols()) : m_.rows(); for (int r = 0; r < active_rows; ++r) { diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h index 416c2143c2c..e7ad14d0ee6 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h +++ b/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h @@ -52,7 +52,7 @@ class DenseSparseMatrix : public SparseMatrix { // m. This assumes that m does not have any repeated entries. explicit DenseSparseMatrix(const TripletSparseMatrix& m); explicit DenseSparseMatrix(const Matrix& m); -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS explicit DenseSparseMatrix(const SparseMatrixProto& proto); #endif @@ -67,7 +67,7 @@ class DenseSparseMatrix : public SparseMatrix { virtual void SquaredColumnNorm(double* x) const; virtual void ScaleColumns(const double* scale); virtual void ToDenseMatrix(Matrix* dense_matrix) const; -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS virtual void ToProto(SparseMatrixProto* proto) const; #endif virtual void ToTextFile(FILE* file) const; diff --git a/extern/libmv/third_party/ceres/internal/ceres/detect_structure.cc b/extern/libmv/third_party/ceres/internal/ceres/detect_structure.cc index e9755043bab..ea5bf2e9690 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/detect_structure.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/detect_structure.cc @@ -28,9 +28,9 @@ // // Author: sameeragarwal@google.com (Sameer Agarwal) -#include #include "ceres/detect_structure.h" #include "ceres/internal/eigen.h" +#include "glog/logging.h" namespace ceres { namespace internal { @@ -60,10 +60,10 @@ void DetectStructure(const CompressedRowBlockStructure& bs, *row_block_size = row.block.size; } else if (*row_block_size != Eigen::Dynamic && *row_block_size != row.block.size) { - *row_block_size = Eigen::Dynamic; VLOG(2) << "Dynamic row block size because the block size changed from " << *row_block_size << " to " << row.block.size; + *row_block_size = Eigen::Dynamic; } @@ -71,10 +71,10 @@ void DetectStructure(const CompressedRowBlockStructure& bs, *e_block_size = bs.cols[e_block_id].size; } else if (*e_block_size != Eigen::Dynamic && *e_block_size != bs.cols[e_block_id].size) { - *e_block_size = Eigen::Dynamic; VLOG(2) << "Dynamic e block size because the block size changed from " << *e_block_size << " to " << bs.cols[e_block_id].size; + *e_block_size = Eigen::Dynamic; } if (*f_block_size == 0) { @@ -85,11 +85,11 @@ void DetectStructure(const CompressedRowBlockStructure& bs, } else if (*f_block_size != Eigen::Dynamic) { for (int c = 1; c < row.cells.size(); ++c) { if (*f_block_size != bs.cols[row.cells[c].block_id].size) { - *f_block_size = Eigen::Dynamic; VLOG(2) << "Dynamic f block size because the block size " - << "changed from " << *f_block_size << " to " - << bs.cols[row.cells[c].block_id].size; - break; + << "changed from " << *f_block_size << " to " + << bs.cols[row.cells[c].block_id].size; + *f_block_size = Eigen::Dynamic; + break; } } } diff --git a/extern/libmv/third_party/ceres/internal/ceres/detect_structure.h b/extern/libmv/third_party/ceres/internal/ceres/detect_structure.h index 8af4f236690..5f8e1b4ff46 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/detect_structure.h +++ b/extern/libmv/third_party/ceres/internal/ceres/detect_structure.h @@ -49,7 +49,7 @@ namespace internal { // is known as compile time. // // For more details about e_blocks and f_blocks, see -// schur_complement.h. This information is used to initialized an +// schur_eliminator.h. This information is used to initialized an // appropriate template specialization of SchurEliminator. void DetectStructure(const CompressedRowBlockStructure& bs, const int num_eliminate_blocks, diff --git a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc new file mode 100644 index 00000000000..668fa54b8b8 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc @@ -0,0 +1,691 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#include "ceres/dogleg_strategy.h" + +#include +#include "Eigen/Dense" +#include "ceres/array_utils.h" +#include "ceres/internal/eigen.h" +#include "ceres/linear_solver.h" +#include "ceres/polynomial_solver.h" +#include "ceres/sparse_matrix.h" +#include "ceres/trust_region_strategy.h" +#include "ceres/types.h" +#include "glog/logging.h" + +namespace ceres { +namespace internal { +namespace { +const double kMaxMu = 1.0; +const double kMinMu = 1e-8; +} + +DoglegStrategy::DoglegStrategy(const TrustRegionStrategy::Options& options) + : linear_solver_(options.linear_solver), + radius_(options.initial_radius), + max_radius_(options.max_radius), + min_diagonal_(options.lm_min_diagonal), + max_diagonal_(options.lm_max_diagonal), + mu_(kMinMu), + min_mu_(kMinMu), + max_mu_(kMaxMu), + mu_increase_factor_(10.0), + increase_threshold_(0.75), + decrease_threshold_(0.25), + dogleg_step_norm_(0.0), + reuse_(false), + dogleg_type_(options.dogleg_type) { + CHECK_NOTNULL(linear_solver_); + CHECK_GT(min_diagonal_, 0.0); + CHECK_LE(min_diagonal_, max_diagonal_); + CHECK_GT(max_radius_, 0.0); +} + +// If the reuse_ flag is not set, then the Cauchy point (scaled +// gradient) and the new Gauss-Newton step are computed from +// scratch. The Dogleg step is then computed as interpolation of these +// two vectors. +TrustRegionStrategy::Summary DoglegStrategy::ComputeStep( + const TrustRegionStrategy::PerSolveOptions& per_solve_options, + SparseMatrix* jacobian, + const double* residuals, + double* step) { + CHECK_NOTNULL(jacobian); + CHECK_NOTNULL(residuals); + CHECK_NOTNULL(step); + + const int n = jacobian->num_cols(); + if (reuse_) { + // Gauss-Newton and gradient vectors are always available, only a + // new interpolant need to be computed. For the subspace case, + // the subspace and the two-dimensional model are also still valid. + switch(dogleg_type_) { + case TRADITIONAL_DOGLEG: + ComputeTraditionalDoglegStep(step); + break; + + case SUBSPACE_DOGLEG: + ComputeSubspaceDoglegStep(step); + break; + } + TrustRegionStrategy::Summary summary; + summary.num_iterations = 0; + summary.termination_type = TOLERANCE; + return summary; + } + + reuse_ = true; + // Check that we have the storage needed to hold the various + // temporary vectors. + if (diagonal_.rows() != n) { + diagonal_.resize(n, 1); + gradient_.resize(n, 1); + gauss_newton_step_.resize(n, 1); + } + + // Vector used to form the diagonal matrix that is used to + // regularize the Gauss-Newton solve and that defines the + // elliptical trust region + // + // || D * step || <= radius_ . + // + jacobian->SquaredColumnNorm(diagonal_.data()); + for (int i = 0; i < n; ++i) { + diagonal_[i] = min(max(diagonal_[i], min_diagonal_), max_diagonal_); + } + diagonal_ = diagonal_.array().sqrt(); + + ComputeGradient(jacobian, residuals); + ComputeCauchyPoint(jacobian); + + LinearSolver::Summary linear_solver_summary = + ComputeGaussNewtonStep(jacobian, residuals); + + TrustRegionStrategy::Summary summary; + summary.residual_norm = linear_solver_summary.residual_norm; + summary.num_iterations = linear_solver_summary.num_iterations; + summary.termination_type = linear_solver_summary.termination_type; + + if (linear_solver_summary.termination_type != FAILURE) { + switch(dogleg_type_) { + // Interpolate the Cauchy point and the Gauss-Newton step. + case TRADITIONAL_DOGLEG: + ComputeTraditionalDoglegStep(step); + break; + + // Find the minimum in the subspace defined by the + // Cauchy point and the (Gauss-)Newton step. + case SUBSPACE_DOGLEG: + if (!ComputeSubspaceModel(jacobian)) { + summary.termination_type = FAILURE; + break; + } + ComputeSubspaceDoglegStep(step); + break; + } + } + + return summary; +} + +// The trust region is assumed to be elliptical with the +// diagonal scaling matrix D defined by sqrt(diagonal_). +// It is implemented by substituting step' = D * step. +// The trust region for step' is spherical. +// The gradient, the Gauss-Newton step, the Cauchy point, +// and all calculations involving the Jacobian have to +// be adjusted accordingly. +void DoglegStrategy::ComputeGradient( + SparseMatrix* jacobian, + const double* residuals) { + gradient_.setZero(); + jacobian->LeftMultiply(residuals, gradient_.data()); + gradient_.array() /= diagonal_.array(); +} + +// The Cauchy point is the global minimizer of the quadratic model +// along the one-dimensional subspace spanned by the gradient. +void DoglegStrategy::ComputeCauchyPoint(SparseMatrix* jacobian) { + // alpha * -gradient is the Cauchy point. + Vector Jg(jacobian->num_rows()); + Jg.setZero(); + // The Jacobian is scaled implicitly by computing J * (D^-1 * (D^-1 * g)) + // instead of (J * D^-1) * (D^-1 * g). + Vector scaled_gradient = + (gradient_.array() / diagonal_.array()).matrix(); + jacobian->RightMultiply(scaled_gradient.data(), Jg.data()); + alpha_ = gradient_.squaredNorm() / Jg.squaredNorm(); +} + +// The dogleg step is defined as the intersection of the trust region +// boundary with the piecewise linear path from the origin to the Cauchy +// point and then from there to the Gauss-Newton point (global minimizer +// of the model function). The Gauss-Newton point is taken if it lies +// within the trust region. +void DoglegStrategy::ComputeTraditionalDoglegStep(double* dogleg) { + VectorRef dogleg_step(dogleg, gradient_.rows()); + + // Case 1. The Gauss-Newton step lies inside the trust region, and + // is therefore the optimal solution to the trust-region problem. + const double gradient_norm = gradient_.norm(); + const double gauss_newton_norm = gauss_newton_step_.norm(); + if (gauss_newton_norm <= radius_) { + dogleg_step = gauss_newton_step_; + dogleg_step_norm_ = gauss_newton_norm; + dogleg_step.array() /= diagonal_.array(); + VLOG(3) << "GaussNewton step size: " << dogleg_step_norm_ + << " radius: " << radius_; + return; + } + + // Case 2. The Cauchy point and the Gauss-Newton steps lie outside + // the trust region. Rescale the Cauchy point to the trust region + // and return. + if (gradient_norm * alpha_ >= radius_) { + dogleg_step = -(radius_ / gradient_norm) * gradient_; + dogleg_step_norm_ = radius_; + dogleg_step.array() /= diagonal_.array(); + VLOG(3) << "Cauchy step size: " << dogleg_step_norm_ + << " radius: " << radius_; + return; + } + + // Case 3. The Cauchy point is inside the trust region and the + // Gauss-Newton step is outside. Compute the line joining the two + // points and the point on it which intersects the trust region + // boundary. + + // a = alpha * -gradient + // b = gauss_newton_step + const double b_dot_a = -alpha_ * gradient_.dot(gauss_newton_step_); + const double a_squared_norm = pow(alpha_ * gradient_norm, 2.0); + const double b_minus_a_squared_norm = + a_squared_norm - 2 * b_dot_a + pow(gauss_newton_norm, 2); + + // c = a' (b - a) + // = alpha * -gradient' gauss_newton_step - alpha^2 |gradient|^2 + const double c = b_dot_a - a_squared_norm; + const double d = sqrt(c * c + b_minus_a_squared_norm * + (pow(radius_, 2.0) - a_squared_norm)); + + double beta = + (c <= 0) + ? (d - c) / b_minus_a_squared_norm + : (radius_ * radius_ - a_squared_norm) / (d + c); + dogleg_step = (-alpha_ * (1.0 - beta)) * gradient_ + + beta * gauss_newton_step_; + dogleg_step_norm_ = dogleg_step.norm(); + dogleg_step.array() /= diagonal_.array(); + VLOG(3) << "Dogleg step size: " << dogleg_step_norm_ + << " radius: " << radius_; +} + +// The subspace method finds the minimum of the two-dimensional problem +// +// min. 1/2 x' B' H B x + g' B x +// s.t. || B x ||^2 <= r^2 +// +// where r is the trust region radius and B is the matrix with unit columns +// spanning the subspace defined by the steepest descent and Newton direction. +// This subspace by definition includes the Gauss-Newton point, which is +// therefore taken if it lies within the trust region. +void DoglegStrategy::ComputeSubspaceDoglegStep(double* dogleg) { + VectorRef dogleg_step(dogleg, gradient_.rows()); + + // The Gauss-Newton point is inside the trust region if |GN| <= radius_. + // This test is valid even though radius_ is a length in the two-dimensional + // subspace while gauss_newton_step_ is expressed in the (scaled) + // higher dimensional original space. This is because + // + // 1. gauss_newton_step_ by definition lies in the subspace, and + // 2. the subspace basis is orthonormal. + // + // As a consequence, the norm of the gauss_newton_step_ in the subspace is + // the same as its norm in the original space. + const double gauss_newton_norm = gauss_newton_step_.norm(); + if (gauss_newton_norm <= radius_) { + dogleg_step = gauss_newton_step_; + dogleg_step_norm_ = gauss_newton_norm; + dogleg_step.array() /= diagonal_.array(); + VLOG(3) << "GaussNewton step size: " << dogleg_step_norm_ + << " radius: " << radius_; + return; + } + + // The optimum lies on the boundary of the trust region. The above problem + // therefore becomes + // + // min. 1/2 x^T B^T H B x + g^T B x + // s.t. || B x ||^2 = r^2 + // + // Notice the equality in the constraint. + // + // This can be solved by forming the Lagrangian, solving for x(y), where + // y is the Lagrange multiplier, using the gradient of the objective, and + // putting x(y) back into the constraint. This results in a fourth order + // polynomial in y, which can be solved using e.g. the companion matrix. + // See the description of MakePolynomialForBoundaryConstrainedProblem for + // details. The result is up to four real roots y*, not all of which + // correspond to feasible points. The feasible points x(y*) have to be + // tested for optimality. + + if (subspace_is_one_dimensional_) { + // The subspace is one-dimensional, so both the gradient and + // the Gauss-Newton step point towards the same direction. + // In this case, we move along the gradient until we reach the trust + // region boundary. + dogleg_step = -(radius_ / gradient_.norm()) * gradient_; + dogleg_step_norm_ = radius_; + dogleg_step.array() /= diagonal_.array(); + VLOG(3) << "Dogleg subspace step size (1D): " << dogleg_step_norm_ + << " radius: " << radius_; + return; + } + + Vector2d minimum(0.0, 0.0); + if (!FindMinimumOnTrustRegionBoundary(&minimum)) { + // For the positive semi-definite case, a traditional dogleg step + // is taken in this case. + LOG(WARNING) << "Failed to compute polynomial roots. " + << "Taking traditional dogleg step instead."; + ComputeTraditionalDoglegStep(dogleg); + return; + } + + // Test first order optimality at the minimum. + // The first order KKT conditions state that the minimum x* + // has to satisfy either || x* ||^2 < r^2 (i.e. has to lie within + // the trust region), or + // + // (B x* + g) + y x* = 0 + // + // for some positive scalar y. + // Here, as it is already known that the minimum lies on the boundary, the + // latter condition is tested. To allow for small imprecisions, we test if + // the angle between (B x* + g) and -x* is smaller than acos(0.99). + // The exact value of the cosine is arbitrary but should be close to 1. + // + // This condition should not be violated. If it is, the minimum was not + // correctly determined. + const double kCosineThreshold = 0.99; + const Vector2d grad_minimum = subspace_B_ * minimum + subspace_g_; + const double cosine_angle = -minimum.dot(grad_minimum) / + (minimum.norm() * grad_minimum.norm()); + if (cosine_angle < kCosineThreshold) { + LOG(WARNING) << "First order optimality seems to be violated " + << "in the subspace method!\n" + << "Cosine of angle between x and B x + g is " + << cosine_angle << ".\n" + << "Taking a regular dogleg step instead.\n" + << "Please consider filing a bug report if this " + << "happens frequently or consistently.\n"; + ComputeTraditionalDoglegStep(dogleg); + return; + } + + // Create the full step from the optimal 2d solution. + dogleg_step = subspace_basis_ * minimum; + dogleg_step_norm_ = radius_; + dogleg_step.array() /= diagonal_.array(); + VLOG(3) << "Dogleg subspace step size: " << dogleg_step_norm_ + << " radius: " << radius_; +} + +// Build the polynomial that defines the optimal Lagrange multipliers. +// Let the Lagrangian be +// +// L(x, y) = 0.5 x^T B x + x^T g + y (0.5 x^T x - 0.5 r^2). (1) +// +// Stationary points of the Lagrangian are given by +// +// 0 = d L(x, y) / dx = Bx + g + y x (2) +// 0 = d L(x, y) / dy = 0.5 x^T x - 0.5 r^2 (3) +// +// For any given y, we can solve (2) for x as +// +// x(y) = -(B + y I)^-1 g . (4) +// +// As B + y I is 2x2, we form the inverse explicitly: +// +// (B + y I)^-1 = (1 / det(B + y I)) adj(B + y I) (5) +// +// where adj() denotes adjugation. This should be safe, as B is positive +// semi-definite and y is necessarily positive, so (B + y I) is indeed +// invertible. +// Plugging (5) into (4) and the result into (3), then dividing by 0.5 we +// obtain +// +// 0 = (1 / det(B + y I))^2 g^T adj(B + y I)^T adj(B + y I) g - r^2 +// (6) +// +// or +// +// det(B + y I)^2 r^2 = g^T adj(B + y I)^T adj(B + y I) g (7a) +// = g^T adj(B)^T adj(B) g +// + 2 y g^T adj(B)^T g + y^2 g^T g (7b) +// +// as +// +// adj(B + y I) = adj(B) + y I = adj(B)^T + y I . (8) +// +// The left hand side can be expressed explicitly using +// +// det(B + y I) = det(B) + y tr(B) + y^2 . (9) +// +// So (7) is a polynomial in y of degree four. +// Bringing everything back to the left hand side, the coefficients can +// be read off as +// +// y^4 r^2 +// + y^3 2 r^2 tr(B) +// + y^2 (r^2 tr(B)^2 + 2 r^2 det(B) - g^T g) +// + y^1 (2 r^2 det(B) tr(B) - 2 g^T adj(B)^T g) +// + y^0 (r^2 det(B)^2 - g^T adj(B)^T adj(B) g) +// +Vector DoglegStrategy::MakePolynomialForBoundaryConstrainedProblem() const { + const double detB = subspace_B_.determinant(); + const double trB = subspace_B_.trace(); + const double r2 = radius_ * radius_; + Matrix2d B_adj; + B_adj << subspace_B_(1,1) , -subspace_B_(0,1), + -subspace_B_(1,0) , subspace_B_(0,0); + + Vector polynomial(5); + polynomial(0) = r2; + polynomial(1) = 2.0 * r2 * trB; + polynomial(2) = r2 * ( trB * trB + 2.0 * detB ) - subspace_g_.squaredNorm(); + polynomial(3) = -2.0 * ( subspace_g_.transpose() * B_adj * subspace_g_ + - r2 * detB * trB ); + polynomial(4) = r2 * detB * detB - (B_adj * subspace_g_).squaredNorm(); + + return polynomial; +} + +// Given a Lagrange multiplier y that corresponds to a stationary point +// of the Lagrangian L(x, y), compute the corresponding x from the +// equation +// +// 0 = d L(x, y) / dx +// = B * x + g + y * x +// = (B + y * I) * x + g +// +DoglegStrategy::Vector2d DoglegStrategy::ComputeSubspaceStepFromRoot( + double y) const { + const Matrix2d B_i = subspace_B_ + y * Matrix2d::Identity(); + return -B_i.partialPivLu().solve(subspace_g_); +} + +// This function evaluates the quadratic model at a point x in the +// subspace spanned by subspace_basis_. +double DoglegStrategy::EvaluateSubspaceModel(const Vector2d& x) const { + return 0.5 * x.dot(subspace_B_ * x) + subspace_g_.dot(x); +} + +// This function attempts to solve the boundary-constrained subspace problem +// +// min. 1/2 x^T B^T H B x + g^T B x +// s.t. || B x ||^2 = r^2 +// +// where B is an orthonormal subspace basis and r is the trust-region radius. +// +// This is done by finding the roots of a fourth degree polynomial. If the +// root finding fails, the function returns false and minimum will be set +// to (0, 0). If it succeeds, true is returned. +// +// In the failure case, another step should be taken, such as the traditional +// dogleg step. +bool DoglegStrategy::FindMinimumOnTrustRegionBoundary(Vector2d* minimum) const { + CHECK_NOTNULL(minimum); + + // Return (0, 0) in all error cases. + minimum->setZero(); + + // Create the fourth-degree polynomial that is a necessary condition for + // optimality. + const Vector polynomial = MakePolynomialForBoundaryConstrainedProblem(); + + // Find the real parts y_i of its roots (not only the real roots). + Vector roots_real; + if (!FindPolynomialRoots(polynomial, &roots_real, NULL)) { + // Failed to find the roots of the polynomial, i.e. the candidate + // solutions of the constrained problem. Report this back to the caller. + return false; + } + + // For each root y, compute B x(y) and check for feasibility. + // Notice that there should always be four roots, as the leading term of + // the polynomial is r^2 and therefore non-zero. However, as some roots + // may be complex, the real parts are not necessarily unique. + double minimum_value = std::numeric_limits::max(); + bool valid_root_found = false; + for (int i = 0; i < roots_real.size(); ++i) { + const Vector2d x_i = ComputeSubspaceStepFromRoot(roots_real(i)); + + // Not all roots correspond to points on the trust region boundary. + // There are at most four candidate solutions. As we are interested + // in the minimum, it is safe to consider all of them after projecting + // them onto the trust region boundary. + if (x_i.norm() > 0) { + const double f_i = EvaluateSubspaceModel((radius_ / x_i.norm()) * x_i); + valid_root_found = true; + if (f_i < minimum_value) { + minimum_value = f_i; + *minimum = x_i; + } + } + } + + return valid_root_found; +} + +LinearSolver::Summary DoglegStrategy::ComputeGaussNewtonStep( + SparseMatrix* jacobian, + const double* residuals) { + const int n = jacobian->num_cols(); + LinearSolver::Summary linear_solver_summary; + linear_solver_summary.termination_type = FAILURE; + + // The Jacobian matrix is often quite poorly conditioned. Thus it is + // necessary to add a diagonal matrix at the bottom to prevent the + // linear solver from failing. + // + // We do this by computing the same diagonal matrix as the one used + // by Levenberg-Marquardt (other choices are possible), and scaling + // it by a small constant (independent of the trust region radius). + // + // If the solve fails, the multiplier to the diagonal is increased + // up to max_mu_ by a factor of mu_increase_factor_ every time. If + // the linear solver is still not successful, the strategy returns + // with FAILURE. + // + // Next time when a new Gauss-Newton step is requested, the + // multiplier starts out from the last successful solve. + // + // When a step is declared successful, the multiplier is decreased + // by half of mu_increase_factor_. + + while (mu_ < max_mu_) { + // Dogleg, as far as I (sameeragarwal) understand it, requires a + // reasonably good estimate of the Gauss-Newton step. This means + // that we need to solve the normal equations more or less + // exactly. This is reflected in the values of the tolerances set + // below. + // + // For now, this strategy should only be used with exact + // factorization based solvers, for which these tolerances are + // automatically satisfied. + // + // The right way to combine inexact solves with trust region + // methods is to use Stiehaug's method. + LinearSolver::PerSolveOptions solve_options; + solve_options.q_tolerance = 0.0; + solve_options.r_tolerance = 0.0; + + lm_diagonal_ = diagonal_ * std::sqrt(mu_); + solve_options.D = lm_diagonal_.data(); + + // As in the LevenbergMarquardtStrategy, solve Jy = r instead + // of Jx = -r and later set x = -y to avoid having to modify + // either jacobian or residuals. + InvalidateArray(n, gauss_newton_step_.data()); + linear_solver_summary = linear_solver_->Solve(jacobian, + residuals, + solve_options, + gauss_newton_step_.data()); + + if (linear_solver_summary.termination_type == FAILURE || + !IsArrayValid(n, gauss_newton_step_.data())) { + mu_ *= mu_increase_factor_; + VLOG(2) << "Increasing mu " << mu_; + linear_solver_summary.termination_type = FAILURE; + continue; + } + break; + } + + if (linear_solver_summary.termination_type != FAILURE) { + // The scaled Gauss-Newton step is D * GN: + // + // - (D^-1 J^T J D^-1)^-1 (D^-1 g) + // = - D (J^T J)^-1 D D^-1 g + // = D -(J^T J)^-1 g + // + gauss_newton_step_.array() *= -diagonal_.array(); + } + + return linear_solver_summary; +} + +void DoglegStrategy::StepAccepted(double step_quality) { + CHECK_GT(step_quality, 0.0); + + if (step_quality < decrease_threshold_) { + radius_ *= 0.5; + } + + if (step_quality > increase_threshold_) { + radius_ = max(radius_, 3.0 * dogleg_step_norm_); + } + + // Reduce the regularization multiplier, in the hope that whatever + // was causing the rank deficiency has gone away and we can return + // to doing a pure Gauss-Newton solve. + mu_ = max(min_mu_, 2.0 * mu_ / mu_increase_factor_ ); + reuse_ = false; +} + +void DoglegStrategy::StepRejected(double step_quality) { + radius_ *= 0.5; + reuse_ = true; +} + +void DoglegStrategy::StepIsInvalid() { + mu_ *= mu_increase_factor_; + reuse_ = false; +} + +double DoglegStrategy::Radius() const { + return radius_; +} + +bool DoglegStrategy::ComputeSubspaceModel(SparseMatrix* jacobian) { + // Compute an orthogonal basis for the subspace using QR decomposition. + Matrix basis_vectors(jacobian->num_cols(), 2); + basis_vectors.col(0) = gradient_; + basis_vectors.col(1) = gauss_newton_step_; + Eigen::ColPivHouseholderQR basis_qr(basis_vectors); + + switch (basis_qr.rank()) { + case 0: + // This should never happen, as it implies that both the gradient + // and the Gauss-Newton step are zero. In this case, the minimizer should + // have stopped due to the gradient being too small. + LOG(ERROR) << "Rank of subspace basis is 0. " + << "This means that the gradient at the current iterate is " + << "zero but the optimization has not been terminated. " + << "You may have found a bug in Ceres."; + return false; + + case 1: + // Gradient and Gauss-Newton step coincide, so we lie on one of the + // major axes of the quadratic problem. In this case, we simply move + // along the gradient until we reach the trust region boundary. + subspace_is_one_dimensional_ = true; + return true; + + case 2: + subspace_is_one_dimensional_ = false; + break; + + default: + LOG(ERROR) << "Rank of the subspace basis matrix is reported to be " + << "greater than 2. As the matrix contains only two " + << "columns this cannot be true and is indicative of " + << "a bug."; + return false; + } + + // The subspace is two-dimensional, so compute the subspace model. + // Given the basis U, this is + // + // subspace_g_ = g_scaled^T U + // + // and + // + // subspace_B_ = U^T (J_scaled^T J_scaled) U + // + // As J_scaled = J * D^-1, the latter becomes + // + // subspace_B_ = ((U^T D^-1) J^T) (J (D^-1 U)) + // = (J (D^-1 U))^T (J (D^-1 U)) + + subspace_basis_ = + basis_qr.householderQ() * Matrix::Identity(jacobian->num_cols(), 2); + + subspace_g_ = subspace_basis_.transpose() * gradient_; + + Eigen::Matrix + Jb(2, jacobian->num_rows()); + Jb.setZero(); + + Vector tmp; + tmp = (subspace_basis_.col(0).array() / diagonal_.array()).matrix(); + jacobian->RightMultiply(tmp.data(), Jb.row(0).data()); + tmp = (subspace_basis_.col(1).array() / diagonal_.array()).matrix(); + jacobian->RightMultiply(tmp.data(), Jb.row(1).data()); + + subspace_B_ = Jb * Jb.transpose(); + + return true; +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h new file mode 100644 index 00000000000..bff1689aa4a --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h @@ -0,0 +1,163 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#ifndef CERES_INTERNAL_DOGLEG_STRATEGY_H_ +#define CERES_INTERNAL_DOGLEG_STRATEGY_H_ + +#include "ceres/linear_solver.h" +#include "ceres/trust_region_strategy.h" + +namespace ceres { +namespace internal { + +// Dogleg step computation and trust region sizing strategy based on +// on "Methods for Nonlinear Least Squares" by K. Madsen, H.B. Nielsen +// and O. Tingleff. Available to download from +// +// http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf +// +// One minor modification is that instead of computing the pure +// Gauss-Newton step, we compute a regularized version of it. This is +// because the Jacobian is often rank-deficient and in such cases +// using a direct solver leads to numerical failure. +// +// If SUBSPACE is passed as the type argument to the constructor, the +// DoglegStrategy follows the approach by Shultz, Schnabel, Byrd. +// This finds the exact optimum over the two-dimensional subspace +// spanned by the two Dogleg vectors. +class DoglegStrategy : public TrustRegionStrategy { +public: + DoglegStrategy(const TrustRegionStrategy::Options& options); + virtual ~DoglegStrategy() {} + + // TrustRegionStrategy interface + virtual Summary ComputeStep(const PerSolveOptions& per_solve_options, + SparseMatrix* jacobian, + const double* residuals, + double* step); + virtual void StepAccepted(double step_quality); + virtual void StepRejected(double step_quality); + virtual void StepIsInvalid(); + + virtual double Radius() const; + + // These functions are predominantly for testing. + Vector gradient() const { return gradient_; } + Vector gauss_newton_step() const { return gauss_newton_step_; } + Matrix subspace_basis() const { return subspace_basis_; } + Vector subspace_g() const { return subspace_g_; } + Matrix subspace_B() const { return subspace_B_; } + + private: + typedef Eigen::Matrix Vector2d; + typedef Eigen::Matrix Matrix2d; + + LinearSolver::Summary ComputeGaussNewtonStep(SparseMatrix* jacobian, + const double* residuals); + void ComputeCauchyPoint(SparseMatrix* jacobian); + void ComputeGradient(SparseMatrix* jacobian, const double* residuals); + void ComputeTraditionalDoglegStep(double* step); + bool ComputeSubspaceModel(SparseMatrix* jacobian); + void ComputeSubspaceDoglegStep(double* step); + + bool FindMinimumOnTrustRegionBoundary(Vector2d* minimum) const; + Vector MakePolynomialForBoundaryConstrainedProblem() const; + Vector2d ComputeSubspaceStepFromRoot(double lambda) const; + double EvaluateSubspaceModel(const Vector2d& x) const; + + LinearSolver* linear_solver_; + double radius_; + const double max_radius_; + + const double min_diagonal_; + const double max_diagonal_; + + // mu is used to scale the diagonal matrix used to make the + // Gauss-Newton solve full rank. In each solve, the strategy starts + // out with mu = min_mu, and tries values upto max_mu. If the user + // reports an invalid step, the value of mu_ is increased so that + // the next solve starts with a stronger regularization. + // + // If a successful step is reported, then the value of mu_ is + // decreased with a lower bound of min_mu_. + double mu_; + const double min_mu_; + const double max_mu_; + const double mu_increase_factor_; + const double increase_threshold_; + const double decrease_threshold_; + + Vector diagonal_; // sqrt(diag(J^T J)) + Vector lm_diagonal_; + + Vector gradient_; + Vector gauss_newton_step_; + + // cauchy_step = alpha * gradient + double alpha_; + double dogleg_step_norm_; + + // When, ComputeStep is called, reuse_ indicates whether the + // Gauss-Newton and Cauchy steps from the last call to ComputeStep + // can be reused or not. + // + // If the user called StepAccepted, then it is expected that the + // user has recomputed the Jacobian matrix and new Gauss-Newton + // solve is needed and reuse is set to false. + // + // If the user called StepRejected, then it is expected that the + // user wants to solve the trust region problem with the same matrix + // but a different trust region radius and the Gauss-Newton and + // Cauchy steps can be reused to compute the Dogleg, thus reuse is + // set to true. + // + // If the user called StepIsInvalid, then there was a numerical + // problem with the step computed in the last call to ComputeStep, + // and the regularization used to do the Gauss-Newton solve is + // increased and a new solve should be done when ComputeStep is + // called again, thus reuse is set to false. + bool reuse_; + + // The dogleg type determines how the minimum of the local + // quadratic model is found. + DoglegType dogleg_type_; + + // If the type is SUBSPACE_DOGLEG, the two-dimensional + // model 1/2 x^T B x + g^T x has to be computed and stored. + bool subspace_is_one_dimensional_; + Matrix subspace_basis_; + Vector2d subspace_g_; + Matrix2d subspace_B_; +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_DOGLEG_STRATEGY_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/evaluator.cc b/extern/libmv/third_party/ceres/internal/ceres/evaluator.cc index ea05aefec8c..a3ce6f04bd4 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/evaluator.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/evaluator.cc @@ -28,14 +28,18 @@ // // Author: keir@google.com (Keir Mierle) -#include -#include "ceres/evaluator.h" +#include #include "ceres/block_evaluate_preparer.h" #include "ceres/block_jacobian_writer.h" #include "ceres/compressed_row_jacobian_writer.h" -#include "ceres/scratch_evaluate_preparer.h" +#include "ceres/compressed_row_sparse_matrix.h" +#include "ceres/crs_matrix.h" #include "ceres/dense_jacobian_writer.h" +#include "ceres/evaluator.h" +#include "ceres/internal/port.h" #include "ceres/program_evaluator.h" +#include "ceres/scratch_evaluate_preparer.h" +#include "glog/logging.h" namespace ceres { namespace internal { @@ -47,6 +51,7 @@ Evaluator* Evaluator::Create(const Evaluator::Options& options, string* error) { switch (options.linear_solver_type) { case DENSE_QR: + case DENSE_NORMAL_CHOLESKY: return new ProgramEvaluator(options, program); @@ -67,5 +72,76 @@ Evaluator* Evaluator::Create(const Evaluator::Options& options, } } +bool Evaluator::Evaluate(Program* program, + int num_threads, + double* cost, + vector* residuals, + vector* gradient, + CRSMatrix* output_jacobian) { + CHECK_GE(num_threads, 1) + << "This is a Ceres bug; please contact the developers!"; + CHECK_NOTNULL(cost); + + // Setup the Parameter indices and offsets before an evaluator can + // be constructed and used. + program->SetParameterOffsetsAndIndex(); + + Evaluator::Options evaluator_options; + evaluator_options.linear_solver_type = SPARSE_NORMAL_CHOLESKY; + evaluator_options.num_threads = num_threads; + + string error; + scoped_ptr evaluator( + Evaluator::Create(evaluator_options, program, &error)); + if (evaluator.get() == NULL) { + LOG(ERROR) << "Unable to create an Evaluator object. " + << "Error: " << error + << "This is a Ceres bug; please contact the developers!"; + return false; + } + + if (residuals !=NULL) { + residuals->resize(evaluator->NumResiduals()); + } + + if (gradient != NULL) { + gradient->resize(evaluator->NumEffectiveParameters()); + } + + scoped_ptr jacobian; + if (output_jacobian != NULL) { + jacobian.reset( + down_cast(evaluator->CreateJacobian())); + } + + // Point the state pointers to the user state pointers. This is + // needed so that we can extract a parameter vector which is then + // passed to Evaluator::Evaluate. + program->SetParameterBlockStatePtrsToUserStatePtrs(); + + // Copy the value of the parameter blocks into a vector, since the + // Evaluate::Evaluate method needs its input as such. The previous + // call to SetParameterBlockStatePtrsToUserStatePtrs ensures that + // these values are the ones corresponding to the actual state of + // the parameter blocks, rather than the temporary state pointer + // used for evaluation. + Vector parameters(program->NumParameters()); + program->ParameterBlocksToStateVector(parameters.data()); + + if (!evaluator->Evaluate(parameters.data(), + cost, + residuals != NULL ? &(*residuals)[0] : NULL, + gradient != NULL ? &(*gradient)[0] : NULL, + jacobian.get())) { + return false; + } + + if (output_jacobian != NULL) { + jacobian->ToCRSMatrix(output_jacobian); + } + + return true; +} + } // namespace internal } // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/evaluator.h b/extern/libmv/third_party/ceres/internal/ceres/evaluator.h index adefdd26660..6aa30d7b739 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/evaluator.h +++ b/extern/libmv/third_party/ceres/internal/ceres/evaluator.h @@ -33,10 +33,14 @@ #define CERES_INTERNAL_EVALUATOR_H_ #include +#include #include "ceres/internal/port.h" #include "ceres/types.h" namespace ceres { + +class CRSMatrix; + namespace internal { class Program; @@ -65,6 +69,32 @@ class Evaluator { Program* program, string* error); + + // This is used for computing the cost, residual and Jacobian for + // returning to the user. For actually solving the optimization + // problem, the optimization algorithm uses the ProgramEvaluator + // objects directly. + // + // The residual, gradients and jacobian pointers can be NULL, in + // which case they will not be evaluated. cost cannot be NULL. + // + // The parallelism of the evaluator is controlled by num_threads; it + // should be at least 1. + // + // Note: That this function does not take a parameter vector as + // input. The parameter blocks are evaluated on the values contained + // in the arrays pointed to by their user_state pointers. + // + // Also worth noting is that this function mutates program by + // calling Program::SetParameterOffsetsAndIndex() on it so that an + // evaluator object can be constructed. + static bool Evaluate(Program* program, + int num_threads, + double* cost, + vector* residuals, + vector* gradient, + CRSMatrix* jacobian); + // Build and return a sparse matrix for storing and working with the Jacobian // of the objective function. The jacobian has dimensions // NumEffectiveParameters() by NumParameters(), and is typically extremely @@ -95,6 +125,7 @@ class Evaluator { virtual bool Evaluate(const double* state, double* cost, double* residuals, + double* gradient, SparseMatrix* jacobian) = 0; // Make a change delta (of size NumEffectiveParameters()) to state (of size diff --git a/extern/libmv/third_party/ceres/internal/ceres/file.cc b/extern/libmv/third_party/ceres/internal/ceres/file.cc index 5fc9d220861..6fe7557246d 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/file.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/file.cc @@ -31,7 +31,8 @@ // Really simple file IO. #include -#include +#include "file.h" +#include "glog/logging.h" namespace ceres { namespace internal { @@ -48,7 +49,7 @@ void WriteStringToFileOrDie(const string &data, const string &filename) { } void ReadFileToStringOrDie(const string &filename, string *data) { - FILE* file_descriptor = file_descriptor = fopen(filename.c_str(), "r"); + FILE* file_descriptor = fopen(filename.c_str(), "r"); if (!file_descriptor) { LOG(FATAL) << "Couldn't read file: " << filename; diff --git a/extern/libmv/third_party/ceres/internal/ceres/generate_eliminator_specialization.py b/extern/libmv/third_party/ceres/internal/ceres/generate_eliminator_specialization.py new file mode 100644 index 00000000000..af9873f94c0 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/generate_eliminator_specialization.py @@ -0,0 +1,186 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2010, 2011, 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +# +# Copyright 2011 Google Inc. All Rights Reserved. +# Author: sameeragarwal@google.com (Sameer Agarwal) +# +# Script for explicitly generating template specialization of the +# SchurEliminator class. It is a rather large class +# and the number of explicit instantiations is also large. Explicitly +# generating these instantiations in separate .cc files breaks the +# compilation into separate compilation unit rather than one large cc +# file which takes 2+GB of RAM to compile. +# +# This script creates two sets of files. +# +# 1. schur_eliminator_x_x_x.cc +# where, the x indicates the template parameters and +# +# 2. schur_eliminator.cc +# +# that contains a factory function for instantiating these classes +# based on runtime parameters. +# +# The list of tuples, specializations indicates the set of +# specializations that is generated. + +# Set of template specializations to generate +SPECIALIZATIONS = [(2, 2, 2), + (2, 2, 3), + (2, 2, 4), + (2, 2, "Dynamic"), + (2, 3, 3), + (2, 3, 4), + (2, 3, 9), + (2, 3, "Dynamic"), + (2, 4, 3), + (2, 4, 4), + (2, 4, "Dynamic"), + (4, 4, 2), + (4, 4, 3), + (4, 4, 4), + (4, 4, "Dynamic"), + ("Dynamic", "Dynamic", "Dynamic")] + +SPECIALIZATION_FILE = """// Copyright 2011 Google Inc. All Rights Reserved. +// Author: sameeragarwal@google.com (Sameer Agarwal) +// +// Template specialization of SchurEliminator. +// +// ======================================== +// THIS FILE IS AUTOGENERATED. DO NOT EDIT. +// THIS FILE IS AUTOGENERATED. DO NOT EDIT. +// THIS FILE IS AUTOGENERATED. DO NOT EDIT. +// THIS FILE IS AUTOGENERATED. DO NOT EDIT. +//========================================= +// +// This file is generated using generate_eliminator_specializations.py. +// Editing it manually is not recommended. + +#include "ceres/schur_eliminator_impl.h" +#include "ceres/internal/eigen.h" + +namespace ceres { +namespace internal { + +template class SchurEliminator<%s, %s, %s>; + +} // namespace internal +} // namespace ceres + +""" + +FACTORY_FILE_HEADER = """// Copyright 2011 Google Inc. All Rights Reserved. +// Author: sameeragarwal@google.com (Sameer Agarwal) +// +// ======================================== +// THIS FILE IS AUTOGENERATED. DO NOT EDIT. +// THIS FILE IS AUTOGENERATED. DO NOT EDIT. +// THIS FILE IS AUTOGENERATED. DO NOT EDIT. +// THIS FILE IS AUTOGENERATED. DO NOT EDIT. +//========================================= +// +// This file is generated using generate_template_specializations.py. +// Editing it manually is not recommended. + +#include "ceres/linear_solver.h" +#include "ceres/schur_eliminator.h" +#include "ceres/internal/eigen.h" + +namespace ceres { +namespace internal { + +SchurEliminatorBase* +SchurEliminatorBase::Create(const LinearSolver::Options& options) { +#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION +""" + +FACTORY_CONDITIONAL = """ if ((options.row_block_size == %s) && + (options.e_block_size == %s) && + (options.f_block_size == %s)) { + return new SchurEliminator<%s, %s, %s>(options); + } +""" + +FACTORY_FOOTER = """ +#endif + VLOG(1) << "Template specializations not found for <" + << options.row_block_size << "," + << options.e_block_size << "," + << options.f_block_size << ">"; + return new SchurEliminator(options); +} + +} // namespace internal +} // namespace ceres +""" + + +def SuffixForSize(size): + if size == "Dynamic": + return "d" + return str(size) + + +def SpecializationFilename(prefix, row_block_size, e_block_size, f_block_size): + return "_".join([prefix] + map(SuffixForSize, (row_block_size, + e_block_size, + f_block_size))) + + +def Specialize(): + """ + Generate specialization code and the conditionals to instantiate it. + """ + f = open("schur_eliminator.cc", "w") + f.write(FACTORY_FILE_HEADER) + + for row_block_size, e_block_size, f_block_size in SPECIALIZATIONS: + output = SpecializationFilename("generated/schur_eliminator", + row_block_size, + e_block_size, + f_block_size) + ".cc" + fptr = open(output, "w") + fptr.write(SPECIALIZATION_FILE % (row_block_size, + e_block_size, + f_block_size)) + fptr.close() + + f.write(FACTORY_CONDITIONAL % (row_block_size, + e_block_size, + f_block_size, + row_block_size, + e_block_size, + f_block_size)) + f.write(FACTORY_FOOTER) + f.close() + + +if __name__ == "__main__": + Specialize() diff --git a/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc b/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc index abba40824ef..7fb3ed7b3a8 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc @@ -36,18 +36,18 @@ #include #include -#include +#include "ceres/cost_function.h" +#include "ceres/internal/eigen.h" +#include "ceres/internal/scoped_ptr.h" #include "ceres/parameter_block.h" +#include "ceres/problem.h" #include "ceres/problem_impl.h" #include "ceres/program.h" #include "ceres/residual_block.h" #include "ceres/runtime_numeric_diff_cost_function.h" #include "ceres/stringprintf.h" -#include "ceres/cost_function.h" -#include "ceres/internal/eigen.h" -#include "ceres/internal/scoped_ptr.h" -#include "ceres/problem.h" #include "ceres/types.h" +#include "glog/logging.h" namespace ceres { namespace internal { diff --git a/extern/libmv/third_party/ceres/internal/ceres/graph.h b/extern/libmv/third_party/ceres/internal/ceres/graph.h index fd7a224f0aa..2c0f6d28e54 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/graph.h +++ b/extern/libmv/third_party/ceres/internal/ceres/graph.h @@ -129,7 +129,7 @@ class Graph { HashMap > edges_; HashMap, double> edge_weights_; - DISALLOW_COPY_AND_ASSIGN(Graph); + CERES_DISALLOW_COPY_AND_ASSIGN(Graph); }; } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/implicit_schur_complement.cc b/extern/libmv/third_party/ceres/internal/ceres/implicit_schur_complement.cc index bd908846362..4af030a8535 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/implicit_schur_complement.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/implicit_schur_complement.cc @@ -30,22 +30,20 @@ #include "ceres/implicit_schur_complement.h" -#include #include "Eigen/Dense" #include "ceres/block_sparse_matrix.h" #include "ceres/block_structure.h" #include "ceres/internal/eigen.h" #include "ceres/internal/scoped_ptr.h" #include "ceres/types.h" +#include "glog/logging.h" namespace ceres { namespace internal { ImplicitSchurComplement::ImplicitSchurComplement(int num_eliminate_blocks, - bool constant_sparsity, bool preconditioner) : num_eliminate_blocks_(num_eliminate_blocks), - constant_sparsity_(constant_sparsity), preconditioner_(preconditioner), A_(NULL), D_(NULL), @@ -62,7 +60,7 @@ void ImplicitSchurComplement::Init(const BlockSparseMatrixBase& A, const double* b) { // Since initialization is reasonably heavy, perhaps we can save on // constructing a new object everytime. - if ((A_ == NULL) || !constant_sparsity_) { + if (A_ == NULL) { A_.reset(new PartitionedMatrixView(A, num_eliminate_blocks_)); } @@ -71,7 +69,7 @@ void ImplicitSchurComplement::Init(const BlockSparseMatrixBase& A, // Initialize temporary storage and compute the block diagonals of // E'E and F'E. - if ((!constant_sparsity_) || (block_diagonal_EtE_inverse_ == NULL)) { + if (block_diagonal_EtE_inverse_ == NULL) { block_diagonal_EtE_inverse_.reset(A_->CreateBlockDiagonalEtE()); if (preconditioner_) { block_diagonal_FtF_inverse_.reset(A_->CreateBlockDiagonalFtF()); @@ -92,17 +90,10 @@ void ImplicitSchurComplement::Init(const BlockSparseMatrixBase& A, // The block diagonals of the augmented linear system contain // contributions from the diagonal D if it is non-null. Add that to // the block diagonals and invert them. - if (D_ != NULL) { - AddDiagonalAndInvert(D_, block_diagonal_EtE_inverse_.get()); - if (preconditioner_) { - AddDiagonalAndInvert(D_ + A_->num_cols_e(), - block_diagonal_FtF_inverse_.get()); - } - } else { - AddDiagonalAndInvert(NULL, block_diagonal_EtE_inverse_.get()); - if (preconditioner_) { - AddDiagonalAndInvert(NULL, block_diagonal_FtF_inverse_.get()); - } + AddDiagonalAndInvert(D_, block_diagonal_EtE_inverse_.get()); + if (preconditioner_) { + AddDiagonalAndInvert((D_ == NULL) ? NULL : D_ + A_->num_cols_e(), + block_diagonal_FtF_inverse_.get()); } // Compute the RHS of the Schur complement system. diff --git a/extern/libmv/third_party/ceres/internal/ceres/implicit_schur_complement.h b/extern/libmv/third_party/ceres/internal/ceres/implicit_schur_complement.h index 37a319f9c57..b9ebaa4628e 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/implicit_schur_complement.h +++ b/extern/libmv/third_party/ceres/internal/ceres/implicit_schur_complement.h @@ -91,20 +91,13 @@ class ImplicitSchurComplement : public LinearOperator { // num_eliminate_blocks is the number of E blocks in the matrix // A. // - // constant_sparsity indicates if across calls to Init, the sparsity - // structure of the matrix A remains constant or not. This makes for - // significant savings across multiple matrices A, e.g. when used in - // conjunction with an optimization algorithm. - // // preconditioner indicates whether the inverse of the matrix F'F // should be computed or not as a preconditioner for the Schur // Complement. // // TODO(sameeragarwal): Get rid of the two bools below and replace // them with enums. - ImplicitSchurComplement(int num_eliminate_blocks, - bool constant_sparsity, - bool preconditioner); + ImplicitSchurComplement(int num_eliminate_blocks, bool preconditioner); virtual ~ImplicitSchurComplement(); // Initialize the Schur complement for a linear least squares @@ -151,7 +144,6 @@ class ImplicitSchurComplement : public LinearOperator { void UpdateRhs(); int num_eliminate_blocks_; - bool constant_sparsity_; bool preconditioner_; scoped_ptr A_; diff --git a/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc index 51303195317..679c41f2431 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc @@ -33,22 +33,18 @@ #include #include #include - -#include #include "Eigen/Dense" #include "ceres/block_sparse_matrix.h" #include "ceres/block_structure.h" #include "ceres/conjugate_gradients_solver.h" #include "ceres/implicit_schur_complement.h" -#include "ceres/linear_solver.h" -#include "ceres/triplet_sparse_matrix.h" -#include "ceres/visibility_based_preconditioner.h" #include "ceres/internal/eigen.h" #include "ceres/internal/scoped_ptr.h" #include "ceres/linear_solver.h" #include "ceres/triplet_sparse_matrix.h" #include "ceres/types.h" #include "ceres/visibility_based_preconditioner.h" +#include "glog/logging.h" namespace ceres { namespace internal { @@ -69,10 +65,9 @@ LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl( CHECK_NOTNULL(A->block_structure()); // Initialize a ImplicitSchurComplement object. - if ((schur_complement_ == NULL) || (!options_.constant_sparsity)) { + if (schur_complement_ == NULL) { schur_complement_.reset( new ImplicitSchurComplement(options_.num_eliminate_blocks, - options_.constant_sparsity, options_.preconditioner_type == JACOBI)); } schur_complement_->Init(*A, per_solve_options.D, b); @@ -119,7 +114,7 @@ LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl( new VisibilityBasedPreconditioner(*A->block_structure(), options_)); } is_preconditioner_good = - visibility_based_preconditioner_->Compute(*A, per_solve_options.D); + visibility_based_preconditioner_->Update(*A, per_solve_options.D); cg_per_solve_options.preconditioner = visibility_based_preconditioner_.get(); break; diff --git a/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt.cc b/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt.cc deleted file mode 100644 index b40a5162adc..00000000000 --- a/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt.cc +++ /dev/null @@ -1,574 +0,0 @@ -// Ceres Solver - A fast non-linear least squares minimizer -// Copyright 2010, 2011, 2012 Google Inc. All rights reserved. -// http://code.google.com/p/ceres-solver/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of Google Inc. nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Author: sameeragarwal@google.com (Sameer Agarwal) -// -// Implementation of a simple LM algorithm which uses the step sizing -// rule of "Methods for Nonlinear Least Squares" by K. Madsen, -// H.B. Nielsen and O. Tingleff. Available to download from -// -// http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf -// -// The basic algorithm described in this note is an exact step -// algorithm that depends on the Newton(LM) step being solved exactly -// in each iteration. When a suitable iterative solver is available to -// solve the Newton(LM) step, the algorithm will automatically switch -// to an inexact step solution method. This trades some slowdown in -// convergence for significant savings in solve time and memory -// usage. Our implementation of the Truncated Newton algorithm follows -// the discussion and recommendataions in "Stephen G. Nash, A Survey -// of Truncated Newton Methods, Journal of Computational and Applied -// Mathematics, 124(1-2), 45-59, 2000. - -#include "ceres/levenberg_marquardt.h" - -#include -#include -#include -#include -#include -#include - -#include -#include "Eigen/Core" -#include "ceres/evaluator.h" -#include "ceres/file.h" -#include "ceres/linear_least_squares_problems.h" -#include "ceres/linear_solver.h" -#include "ceres/matrix_proto.h" -#include "ceres/sparse_matrix.h" -#include "ceres/stringprintf.h" -#include "ceres/internal/eigen.h" -#include "ceres/internal/scoped_ptr.h" -#include "ceres/types.h" - -namespace ceres { -namespace internal { -namespace { - -// Numbers for clamping the size of the LM diagonal. The size of these -// numbers is heuristic. We will probably be adjusting them in the -// future based on more numerical experience. With jacobi scaling -// enabled, these numbers should be all but redundant. -const double kMinLevenbergMarquardtDiagonal = 1e-6; -const double kMaxLevenbergMarquardtDiagonal = 1e32; - -// Small constant for various floating point issues. -const double kEpsilon = 1e-12; - -// Number of times the linear solver should be retried in case of -// numerical failure. The retries are done by exponentially scaling up -// mu at each retry. This leads to stronger and stronger -// regularization making the linear least squares problem better -// conditioned at each retry. -const int kMaxLinearSolverRetries = 5; - -// D = 1/sqrt(diag(J^T * J)) -void EstimateScale(const SparseMatrix& jacobian, double* D) { - CHECK_NOTNULL(D); - jacobian.SquaredColumnNorm(D); - for (int i = 0; i < jacobian.num_cols(); ++i) { - D[i] = 1.0 / (kEpsilon + sqrt(D[i])); - } -} - -// D = diag(J^T * J) -void LevenbergMarquardtDiagonal(const SparseMatrix& jacobian, - double* D) { - CHECK_NOTNULL(D); - jacobian.SquaredColumnNorm(D); - for (int i = 0; i < jacobian.num_cols(); ++i) { - D[i] = min(max(D[i], kMinLevenbergMarquardtDiagonal), - kMaxLevenbergMarquardtDiagonal); - } -} - -bool RunCallback(IterationCallback* callback, - const IterationSummary& iteration_summary, - Solver::Summary* summary) { - const CallbackReturnType status = (*callback)(iteration_summary); - switch (status) { - case SOLVER_TERMINATE_SUCCESSFULLY: - summary->termination_type = USER_SUCCESS; - VLOG(1) << "Terminating on USER_SUCCESS."; - return false; - case SOLVER_ABORT: - summary->termination_type = USER_ABORT; - VLOG(1) << "Terminating on USER_ABORT."; - return false; - case SOLVER_CONTINUE: - return true; - default: - LOG(FATAL) << "Unknown status returned by callback: " - << status; - return NULL; - } -} - -} // namespace - -LevenbergMarquardt::~LevenbergMarquardt() {} - -void LevenbergMarquardt::Minimize(const Minimizer::Options& options, - Evaluator* evaluator, - LinearSolver* linear_solver, - const double* initial_parameters, - double* final_parameters, - Solver::Summary* summary) { - time_t start_time = time(NULL); - const int num_parameters = evaluator->NumParameters(); - const int num_effective_parameters = evaluator->NumEffectiveParameters(); - const int num_residuals = evaluator->NumResiduals(); - - summary->termination_type = NO_CONVERGENCE; - summary->num_successful_steps = 0; - summary->num_unsuccessful_steps = 0; - - // Allocate the various vectors needed by the algorithm. - memcpy(final_parameters, initial_parameters, - num_parameters * sizeof(*initial_parameters)); - - VectorRef x(final_parameters, num_parameters); - Vector x_new(num_parameters); - - Vector lm_step(num_effective_parameters); - Vector gradient(num_effective_parameters); - Vector scaled_gradient(num_effective_parameters); - // Jacobi scaling vector - Vector scale(num_effective_parameters); - - Vector f_model(num_residuals); - Vector f(num_residuals); - Vector f_new(num_residuals); - Vector D(num_parameters); - Vector muD(num_parameters); - - // Ask the Evaluator to create the jacobian matrix. The sparsity - // pattern of this matrix is going to remain constant, so we only do - // this once and then re-use this matrix for all subsequent Jacobian - // computations. - scoped_ptr jacobian(evaluator->CreateJacobian()); - - double x_norm = x.norm(); - - double cost = 0.0; - D.setOnes(); - f.setZero(); - - // Do initial cost and Jacobian evaluation. - if (!evaluator->Evaluate(x.data(), &cost, f.data(), jacobian.get())) { - LOG(WARNING) << "Failed to compute residuals and Jacobian. " - << "Terminating."; - summary->termination_type = NUMERICAL_FAILURE; - return; - } - - if (options.jacobi_scaling) { - EstimateScale(*jacobian, scale.data()); - jacobian->ScaleColumns(scale.data()); - } else { - scale.setOnes(); - } - - // This is a poor way to do this computation. Even if fixed_cost is - // zero, because we are subtracting two possibly large numbers, we - // are depending on exact cancellation to give us a zero here. But - // initial_cost and cost have been computed by two different - // evaluators. One which runs on the whole problem (in - // solver_impl.cc) in single threaded mode and another which runs - // here on the reduced problem, so fixed_cost can (and does) contain - // some numerical garbage with a relative magnitude of 1e-14. - // - // The right way to do this, would be to compute the fixed cost on - // just the set of residual blocks which are held constant and were - // removed from the original problem when the reduced problem was - // constructed. - summary->fixed_cost = summary->initial_cost - cost; - - double model_cost = f.squaredNorm() / 2.0; - double total_cost = summary->fixed_cost + cost; - - scaled_gradient.setZero(); - jacobian->LeftMultiply(f.data(), scaled_gradient.data()); - gradient = scaled_gradient.array() / scale.array(); - - double gradient_max_norm = gradient.lpNorm(); - // We need the max here to guard againt the gradient being zero. - const double gradient_max_norm_0 = max(gradient_max_norm, kEpsilon); - double gradient_tolerance = options.gradient_tolerance * gradient_max_norm_0; - - double mu = options.tau; - double nu = 2.0; - int iteration = 0; - double actual_cost_change = 0.0; - double step_norm = 0.0; - double relative_decrease = 0.0; - - // Insane steps are steps which are not sane, i.e. there is some - // numerical kookiness going on with them. There are various reasons - // for this kookiness, some easier to diagnose then others. From the - // point of view of the non-linear solver, they are steps which - // cannot be used. We return with NUMERICAL_FAILURE after - // kMaxLinearSolverRetries consecutive insane steps. - bool step_is_sane = false; - int num_consecutive_insane_steps = 0; - - // Whether the step resulted in a sufficient decrease in the - // objective function when compared to the decrease in the value of - // the lineariztion. - bool step_is_successful = false; - - // Parse the iterations for which to dump the linear problem. - vector iterations_to_dump = options.lsqp_iterations_to_dump; - sort(iterations_to_dump.begin(), iterations_to_dump.end()); - - IterationSummary iteration_summary; - iteration_summary.iteration = iteration; - iteration_summary.step_is_successful = false; - iteration_summary.cost = total_cost; - iteration_summary.cost_change = actual_cost_change; - iteration_summary.gradient_max_norm = gradient_max_norm; - iteration_summary.step_norm = step_norm; - iteration_summary.relative_decrease = relative_decrease; - iteration_summary.mu = mu; - iteration_summary.eta = options.eta; - iteration_summary.linear_solver_iterations = 0; - iteration_summary.linear_solver_time_sec = 0.0; - iteration_summary.iteration_time_sec = (time(NULL) - start_time); - if (options.logging_type >= PER_MINIMIZER_ITERATION) { - summary->iterations.push_back(iteration_summary); - } - - // Check if the starting point is an optimum. - VLOG(2) << "Gradient max norm: " << gradient_max_norm - << " tolerance: " << gradient_tolerance - << " ratio: " << gradient_max_norm / gradient_max_norm_0 - << " tolerance: " << options.gradient_tolerance; - if (gradient_max_norm <= gradient_tolerance) { - summary->termination_type = GRADIENT_TOLERANCE; - VLOG(1) << "Terminating on GRADIENT_TOLERANCE. " - << "Relative gradient max norm: " - << gradient_max_norm / gradient_max_norm_0 - << " <= " << options.gradient_tolerance; - return; - } - - // Call the various callbacks. - for (int i = 0; i < options.callbacks.size(); ++i) { - if (!RunCallback(options.callbacks[i], iteration_summary, summary)) { - return; - } - } - - // We only need the LM diagonal if we are actually going to do at - // least one iteration of the optimization. So we wait to do it - // until now. - LevenbergMarquardtDiagonal(*jacobian, D.data()); - - while ((iteration < options.max_num_iterations) && - (time(NULL) - start_time) <= options.max_solver_time_sec) { - time_t iteration_start_time = time(NULL); - step_is_sane = false; - step_is_successful = false; - - IterationSummary iteration_summary; - // The while loop here is just to provide an easily breakable - // control structure. We are guaranteed to always exit this loop - // at the end of one iteration or before. - while (1) { - muD = (mu * D).array().sqrt(); - LinearSolver::PerSolveOptions solve_options; - solve_options.D = muD.data(); - solve_options.q_tolerance = options.eta; - // Disable r_tolerance checking. Since we only care about - // termination via the q_tolerance. As Nash and Sofer show, - // r_tolerance based termination is essentially useless in - // Truncated Newton methods. - solve_options.r_tolerance = -1.0; - - const time_t linear_solver_start_time = time(NULL); - LinearSolver::Summary linear_solver_summary = - linear_solver->Solve(jacobian.get(), - f.data(), - solve_options, - lm_step.data()); - iteration_summary.linear_solver_time_sec = - (time(NULL) - linear_solver_start_time); - iteration_summary.linear_solver_iterations = - linear_solver_summary.num_iterations; - - if (binary_search(iterations_to_dump.begin(), - iterations_to_dump.end(), - iteration)) { - CHECK(DumpLinearLeastSquaresProblem(options.lsqp_dump_directory, - iteration, - options.lsqp_dump_format_type, - jacobian.get(), - muD.data(), - f.data(), - lm_step.data(), - options.num_eliminate_blocks)) - << "Tried writing linear least squares problem: " - << options.lsqp_dump_directory - << " but failed."; - } - - // We ignore the case where the linear solver did not converge, - // since the partial solution computed by it still maybe of use, - // and there is no reason to ignore it, especially since we - // spent so much time computing it. - if ((linear_solver_summary.termination_type != TOLERANCE) && - (linear_solver_summary.termination_type != MAX_ITERATIONS)) { - VLOG(1) << "Linear solver failure: retrying with a higher mu"; - break; - } - - step_norm = (lm_step.array() * scale.array()).matrix().norm(); - - // Check step length based convergence. If the step length is - // too small, then we are done. - const double step_size_tolerance = options.parameter_tolerance * - (x_norm + options.parameter_tolerance); - - VLOG(2) << "Step size: " << step_norm - << " tolerance: " << step_size_tolerance - << " ratio: " << step_norm / step_size_tolerance - << " tolerance: " << options.parameter_tolerance; - if (step_norm <= options.parameter_tolerance * - (x_norm + options.parameter_tolerance)) { - summary->termination_type = PARAMETER_TOLERANCE; - VLOG(1) << "Terminating on PARAMETER_TOLERANCE." - << "Relative step size: " << step_norm / step_size_tolerance - << " <= " << options.parameter_tolerance; - return; - } - - Vector delta = -(lm_step.array() * scale.array()).matrix(); - if (!evaluator->Plus(x.data(), delta.data(), x_new.data())) { - LOG(WARNING) << "Failed to compute Plus(x, delta, x_plus_delta). " - << "Terminating."; - summary->termination_type = NUMERICAL_FAILURE; - return; - } - - double cost_new = 0.0; - if (!evaluator->Evaluate(x_new.data(), &cost_new, NULL, NULL)) { - LOG(WARNING) << "Failed to compute the value of the objective " - << "function. Terminating."; - summary->termination_type = NUMERICAL_FAILURE; - return; - } - - f_model.setZero(); - jacobian->RightMultiply(lm_step.data(), f_model.data()); - const double model_cost_new = - (f.segment(0, num_residuals) - f_model).squaredNorm() / 2; - - actual_cost_change = cost - cost_new; - double model_cost_change = model_cost - model_cost_new; - - VLOG(2) << "[Model cost] current: " << model_cost - << " new : " << model_cost_new - << " change: " << model_cost_change; - - VLOG(2) << "[Nonlinear cost] current: " << cost - << " new : " << cost_new - << " change: " << actual_cost_change - << " relative change: " << fabs(actual_cost_change) / cost - << " tolerance: " << options.function_tolerance; - - // In exact arithmetic model_cost_change should never be - // negative. But due to numerical precision issues, we may end up - // with a small negative number. model_cost_change which are - // negative and large in absolute value are indicative of a - // numerical failure in the solver. - if (model_cost_change < -kEpsilon) { - VLOG(1) << "Model cost change is negative.\n" - << "Current : " << model_cost - << " new : " << model_cost_new - << " change: " << model_cost_change << "\n"; - break; - } - - // If we have reached this far, then we are willing to trust the - // numerical quality of the step. - step_is_sane = true; - num_consecutive_insane_steps = 0; - - // Check function value based convergence. - if (fabs(actual_cost_change) < options.function_tolerance * cost) { - VLOG(1) << "Termination on FUNCTION_TOLERANCE." - << " Relative cost change: " << fabs(actual_cost_change) / cost - << " tolerance: " << options.function_tolerance; - summary->termination_type = FUNCTION_TOLERANCE; - return; - } - - // Clamp model_cost_change at kEpsilon from below. - if (model_cost_change < kEpsilon) { - VLOG(1) << "Clamping model cost change " << model_cost_change - << " to " << kEpsilon; - model_cost_change = kEpsilon; - } - - relative_decrease = actual_cost_change / model_cost_change; - VLOG(2) << "actual_cost_change / model_cost_change = " - << relative_decrease; - - if (relative_decrease < options.min_relative_decrease) { - VLOG(2) << "Unsuccessful step."; - break; - } - - VLOG(2) << "Successful step."; - - ++summary->num_successful_steps; - x = x_new; - x_norm = x.norm(); - - if (!evaluator->Evaluate(x.data(), &cost, f.data(), jacobian.get())) { - LOG(WARNING) << "Failed to compute residuals and jacobian. " - << "Terminating."; - summary->termination_type = NUMERICAL_FAILURE; - return; - } - - if (options.jacobi_scaling) { - jacobian->ScaleColumns(scale.data()); - } - - model_cost = f.squaredNorm() / 2.0; - LevenbergMarquardtDiagonal(*jacobian, D.data()); - scaled_gradient.setZero(); - jacobian->LeftMultiply(f.data(), scaled_gradient.data()); - gradient = scaled_gradient.array() / scale.array(); - gradient_max_norm = gradient.lpNorm(); - - // Check gradient based convergence. - VLOG(2) << "Gradient max norm: " << gradient_max_norm - << " tolerance: " << gradient_tolerance - << " ratio: " << gradient_max_norm / gradient_max_norm_0 - << " tolerance: " << options.gradient_tolerance; - if (gradient_max_norm <= gradient_tolerance) { - summary->termination_type = GRADIENT_TOLERANCE; - VLOG(1) << "Terminating on GRADIENT_TOLERANCE. " - << "Relative gradient max norm: " - << gradient_max_norm / gradient_max_norm_0 - << " <= " << options.gradient_tolerance - << " (tolerance)."; - return; - } - - mu = mu * max(1.0 / 3.0, 1 - pow(2 * relative_decrease - 1, 3)); - nu = 2.0; - step_is_successful = true; - break; - } - - if (!step_is_sane) { - ++num_consecutive_insane_steps; - } - - if (num_consecutive_insane_steps == kMaxLinearSolverRetries) { - summary->termination_type = NUMERICAL_FAILURE; - VLOG(1) << "Too many consecutive retries; ending with numerical fail."; - - if (!options.crash_and_dump_lsqp_on_failure) { - return; - } - - // Dump debugging information to disk. - CHECK(options.lsqp_dump_format_type == TEXTFILE || - options.lsqp_dump_format_type == PROTOBUF) - << "Dumping the linear least squares problem on crash " - << "requires Solver::Options::lsqp_dump_format_type to be " - << "PROTOBUF or TEXTFILE."; - - if (DumpLinearLeastSquaresProblem(options.lsqp_dump_directory, - iteration, - options.lsqp_dump_format_type, - jacobian.get(), - muD.data(), - f.data(), - lm_step.data(), - options.num_eliminate_blocks)) { - LOG(FATAL) << "Linear least squares problem saved to: " - << options.lsqp_dump_directory - << ". Please provide this to the Ceres developers for " - << " debugging along with the v=2 log."; - } else { - LOG(FATAL) << "Tried writing linear least squares problem: " - << options.lsqp_dump_directory - << " but failed."; - } - } - - if (!step_is_successful) { - // Either the step did not lead to a decrease in cost or there - // was numerical failure. In either case we will scale mu up and - // retry. If it was a numerical failure, we hope that the - // stronger regularization will make the linear system better - // conditioned. If it was numerically sane, but there was no - // decrease in cost, then increasing mu reduces the size of the - // trust region and we look for a decrease closer to the - // linearization point. - ++summary->num_unsuccessful_steps; - mu = mu * nu; - nu = 2 * nu; - } - - ++iteration; - - total_cost = summary->fixed_cost + cost; - - iteration_summary.iteration = iteration; - iteration_summary.step_is_successful = step_is_successful; - iteration_summary.cost = total_cost; - iteration_summary.cost_change = actual_cost_change; - iteration_summary.gradient_max_norm = gradient_max_norm; - iteration_summary.step_norm = step_norm; - iteration_summary.relative_decrease = relative_decrease; - iteration_summary.mu = mu; - iteration_summary.eta = options.eta; - iteration_summary.iteration_time_sec = (time(NULL) - iteration_start_time); - - if (options.logging_type >= PER_MINIMIZER_ITERATION) { - summary->iterations.push_back(iteration_summary); - } - - // Call the various callbacks. - for (int i = 0; i < options.callbacks.size(); ++i) { - if (!RunCallback(options.callbacks[i], iteration_summary, summary)) { - return; - } - } - } -} - -} // namespace internal -} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt.h b/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt.h deleted file mode 100644 index d00bb9095be..00000000000 --- a/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt.h +++ /dev/null @@ -1,65 +0,0 @@ -// Ceres Solver - A fast non-linear least squares minimizer -// Copyright 2010, 2011, 2012 Google Inc. All rights reserved. -// http://code.google.com/p/ceres-solver/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of Google Inc. nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Author: sameeragarwal@google.com (Sameer Agarwal) -// -// Implmentation of Levenberg Marquardt algorithm based on "Methods for -// Nonlinear Least Squares" by K. Madsen, H.B. Nielsen and -// O. Tingleff. Available to download from -// -// http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf -// - -#ifndef CERES_INTERNAL_LEVENBERG_MARQUARDT_H_ -#define CERES_INTERNAL_LEVENBERG_MARQUARDT_H_ - -#include "ceres/minimizer.h" -#include "ceres/solver.h" - -namespace ceres { -namespace internal { - -class Evaluator; -class LinearSolver; - -class LevenbergMarquardt : public Minimizer { - public: - virtual ~LevenbergMarquardt(); - - virtual void Minimize(const Minimizer::Options& options, - Evaluator* evaluator, - LinearSolver* linear_solver, - const double* initial_parameters, - double* final_parameters, - Solver::Summary* summary); -}; - -} // namespace internal -} // namespace ceres - -#endif // CERES_INTERNAL_LEVENBERG_MARQUARDT_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.cc b/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.cc new file mode 100644 index 00000000000..9e6a59e3813 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.cc @@ -0,0 +1,144 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#include "ceres/levenberg_marquardt_strategy.h" + +#include +#include "Eigen/Core" +#include "ceres/array_utils.h" +#include "ceres/internal/eigen.h" +#include "ceres/linear_solver.h" +#include "ceres/sparse_matrix.h" +#include "ceres/trust_region_strategy.h" +#include "ceres/types.h" +#include "glog/logging.h" + +namespace ceres { +namespace internal { + +LevenbergMarquardtStrategy::LevenbergMarquardtStrategy( + const TrustRegionStrategy::Options& options) + : linear_solver_(options.linear_solver), + radius_(options.initial_radius), + max_radius_(options.max_radius), + min_diagonal_(options.lm_min_diagonal), + max_diagonal_(options.lm_max_diagonal), + decrease_factor_(2.0), + reuse_diagonal_(false) { + CHECK_NOTNULL(linear_solver_); + CHECK_GT(min_diagonal_, 0.0); + CHECK_LE(min_diagonal_, max_diagonal_); + CHECK_GT(max_radius_, 0.0); +} + +LevenbergMarquardtStrategy::~LevenbergMarquardtStrategy() { +} + +TrustRegionStrategy::Summary LevenbergMarquardtStrategy::ComputeStep( + const TrustRegionStrategy::PerSolveOptions& per_solve_options, + SparseMatrix* jacobian, + const double* residuals, + double* step) { + CHECK_NOTNULL(jacobian); + CHECK_NOTNULL(residuals); + CHECK_NOTNULL(step); + + const int num_parameters = jacobian->num_cols(); + if (!reuse_diagonal_) { + if (diagonal_.rows() != num_parameters) { + diagonal_.resize(num_parameters, 1); + } + + jacobian->SquaredColumnNorm(diagonal_.data()); + for (int i = 0; i < num_parameters; ++i) { + diagonal_[i] = min(max(diagonal_[i], min_diagonal_), max_diagonal_); + } + } + + lm_diagonal_ = (diagonal_ / radius_).array().sqrt(); + + LinearSolver::PerSolveOptions solve_options; + solve_options.D = lm_diagonal_.data(); + solve_options.q_tolerance = per_solve_options.eta; + // Disable r_tolerance checking. Since we only care about + // termination via the q_tolerance. As Nash and Sofer show, + // r_tolerance based termination is essentially useless in + // Truncated Newton methods. + solve_options.r_tolerance = -1.0; + + // Invalidate the output array lm_step, so that we can detect if + // the linear solver generated numerical garbage. This is known + // to happen for the DENSE_QR and then DENSE_SCHUR solver when + // the Jacobin is severly rank deficient and mu is too small. + InvalidateArray(num_parameters, step); + + // Instead of solving Jx = -r, solve Jy = r. + // Then x can be found as x = -y, but the inputs jacobian and residuals + // do not need to be modified. + LinearSolver::Summary linear_solver_summary = + linear_solver_->Solve(jacobian, residuals, solve_options, step); + if (linear_solver_summary.termination_type == FAILURE || + !IsArrayValid(num_parameters, step)) { + LOG(WARNING) << "Linear solver failure. Failed to compute a finite step."; + linear_solver_summary.termination_type = FAILURE; + } else { + VectorRef(step, num_parameters) *= -1.0; + } + + reuse_diagonal_ = true; + + TrustRegionStrategy::Summary summary; + summary.residual_norm = linear_solver_summary.residual_norm; + summary.num_iterations = linear_solver_summary.num_iterations; + summary.termination_type = linear_solver_summary.termination_type; + return summary; +} + +void LevenbergMarquardtStrategy::StepAccepted(double step_quality) { + CHECK_GT(step_quality, 0.0); + radius_ = radius_ / std::max(1.0 / 3.0, + 1.0 - pow(2.0 * step_quality - 1.0, 3)); + radius_ = std::min(max_radius_, radius_); + decrease_factor_ = 2.0; + reuse_diagonal_ = false; +} + +void LevenbergMarquardtStrategy::StepRejected(double step_quality) { + radius_ = radius_ / decrease_factor_; + decrease_factor_ *= 2.0; + reuse_diagonal_ = true; +} + +double LevenbergMarquardtStrategy::Radius() const { + return radius_; +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h b/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h new file mode 100644 index 00000000000..90c21789797 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h @@ -0,0 +1,86 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#ifndef CERES_INTERNAL_LEVENBERG_MARQUARDT_STRATEGY_H_ +#define CERES_INTERNAL_LEVENBERG_MARQUARDT_STRATEGY_H_ + +#include "ceres/internal/eigen.h" +#include "ceres/trust_region_strategy.h" + +namespace ceres { +namespace internal { + +// Levenberg-Marquardt step computation and trust region sizing +// strategy based on on "Methods for Nonlinear Least Squares" by +// K. Madsen, H.B. Nielsen and O. Tingleff. Available to download from +// +// http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf +class LevenbergMarquardtStrategy : public TrustRegionStrategy { +public: + LevenbergMarquardtStrategy(const TrustRegionStrategy::Options& options); + virtual ~LevenbergMarquardtStrategy(); + + // TrustRegionStrategy interface + virtual TrustRegionStrategy::Summary ComputeStep( + const TrustRegionStrategy::PerSolveOptions& per_solve_options, + SparseMatrix* jacobian, + const double* residuals, + double* step); + virtual void StepAccepted(double step_quality); + virtual void StepRejected(double step_quality); + virtual void StepIsInvalid() { + // Treat the current step as a rejected step with no increase in + // solution quality. Since rejected steps lead to decrease in the + // size of the trust region, the next time ComputeStep is called, + // this will lead to a better conditioned system. + StepRejected(0.0); + } + + virtual double Radius() const; + + private: + LinearSolver* linear_solver_; + double radius_; + double max_radius_; + const double min_diagonal_; + const double max_diagonal_; + double decrease_factor_; + bool reuse_diagonal_; + Vector diagonal_; // diagonal_ = diag(J'J) + // Scaled copy of diagonal_. Stored here as optimization to prevent + // allocations in every iteration and reuse when a step fails and + // ComputeStep is called again. + Vector lm_diagonal_; // lm_diagonal_ = diagonal_ / radius_; +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_LEVENBERG_MARQUARDT_STRATEGY_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc b/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc index cca9f442fe7..a91e254a663 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc @@ -33,17 +33,17 @@ #include #include #include -#include #include "ceres/block_sparse_matrix.h" #include "ceres/block_structure.h" #include "ceres/casts.h" #include "ceres/compressed_row_sparse_matrix.h" #include "ceres/file.h" +#include "ceres/internal/scoped_ptr.h" #include "ceres/matrix_proto.h" -#include "ceres/triplet_sparse_matrix.h" #include "ceres/stringprintf.h" -#include "ceres/internal/scoped_ptr.h" +#include "ceres/triplet_sparse_matrix.h" #include "ceres/types.h" +#include "glog/logging.h" namespace ceres { namespace internal { @@ -64,7 +64,7 @@ LinearLeastSquaresProblem* CreateLinearLeastSquaresProblemFromId(int id) { return NULL; } -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS LinearLeastSquaresProblem* CreateLinearLeastSquaresProblemFromFile( const string& filename) { LinearLeastSquaresProblemProto problem_proto; @@ -130,7 +130,7 @@ LinearLeastSquaresProblem* CreateLinearLeastSquaresProblemFromFile( << "Ceres to be built with Protocol Buffers support."; return NULL; } -#endif // CERES_DONT_HAVE_PROTOCOL_BUFFERS +#endif // CERES_NO_PROTOCOL_BUFFERS /* A = [1 2] @@ -573,13 +573,13 @@ LinearLeastSquaresProblem* LinearLeastSquaresProblem3() { return problem; } -bool DumpLinearLeastSquaresProblemToConsole(const string& directory, - int iteration, - const SparseMatrix* A, - const double* D, - const double* b, - const double* x, - int num_eliminate_blocks) { +static bool DumpLinearLeastSquaresProblemToConsole(const string& directory, + int iteration, + const SparseMatrix* A, + const double* D, + const double* b, + const double* x, + int num_eliminate_blocks) { CHECK_NOTNULL(A); Matrix AA; A->ToDenseMatrix(&AA); @@ -600,14 +600,14 @@ bool DumpLinearLeastSquaresProblemToConsole(const string& directory, return true; }; -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS -bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, - int iteration, - const SparseMatrix* A, - const double* D, - const double* b, - const double* x, - int num_eliminate_blocks) { +#ifndef CERES_NO_PROTOCOL_BUFFERS +static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, + int iteration, + const SparseMatrix* A, + const double* D, + const double* b, + const double* x, + int num_eliminate_blocks) { CHECK_NOTNULL(A); LinearLeastSquaresProblemProto lsqp; A->ToProto(lsqp.mutable_a()); @@ -641,13 +641,13 @@ bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, return true; } #else -bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, - int iteration, - const SparseMatrix* A, - const double* D, - const double* b, - const double* x, - int num_eliminate_blocks) { +static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, + int iteration, + const SparseMatrix* A, + const double* D, + const double* b, + const double* x, + int num_eliminate_blocks) { LOG(ERROR) << "Dumping least squares problems is only " << "supported when Ceres is compiled with " << "protocol buffer support."; @@ -655,9 +655,9 @@ bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, } #endif -void WriteArrayToFileOrDie(const string& filename, - const double* x, - const int size) { +static void WriteArrayToFileOrDie(const string& filename, + const double* x, + const int size) { CHECK_NOTNULL(x); VLOG(2) << "Writing array to: " << filename; FILE* fptr = fopen(filename.c_str(), "w"); @@ -668,43 +668,68 @@ void WriteArrayToFileOrDie(const string& filename, fclose(fptr); } -bool DumpLinearLeastSquaresProblemToTextFile(const string& directory, - int iteration, - const SparseMatrix* A, - const double* D, - const double* b, - const double* x, - int num_eliminate_blocks) { +static bool DumpLinearLeastSquaresProblemToTextFile(const string& directory, + int iteration, + const SparseMatrix* A, + const double* D, + const double* b, + const double* x, + int num_eliminate_blocks) { CHECK_NOTNULL(A); string format_string = JoinPath(directory, "lm_iteration_%03d"); string filename_prefix = StringPrintf(format_string.c_str(), iteration); + LOG(INFO) << "writing to: " << filename_prefix << "*"; + + string matlab_script; + StringAppendF(&matlab_script, + "function lsqp = lm_iteration_%03d()\n", iteration); + StringAppendF(&matlab_script, + "lsqp.num_rows = %d;\n", A->num_rows()); + StringAppendF(&matlab_script, + "lsqp.num_cols = %d;\n", A->num_cols()); + { string filename = filename_prefix + "_A.txt"; - LOG(INFO) << "writing to: " << filename; FILE* fptr = fopen(filename.c_str(), "w"); CHECK_NOTNULL(fptr); A->ToTextFile(fptr); fclose(fptr); + StringAppendF(&matlab_script, + "tmp = load('%s', '-ascii');\n", filename.c_str()); + StringAppendF( + &matlab_script, + "lsqp.A = sparse(tmp(:, 1) + 1, tmp(:, 2) + 1, tmp(:, 3), %d, %d);\n", + A->num_rows(), + A->num_cols()); } + if (D != NULL) { string filename = filename_prefix + "_D.txt"; WriteArrayToFileOrDie(filename, D, A->num_cols()); + StringAppendF(&matlab_script, + "lsqp.D = load('%s', '-ascii');\n", filename.c_str()); } if (b != NULL) { string filename = filename_prefix + "_b.txt"; WriteArrayToFileOrDie(filename, b, A->num_rows()); + StringAppendF(&matlab_script, + "lsqp.b = load('%s', '-ascii');\n", filename.c_str()); } if (x != NULL) { string filename = filename_prefix + "_x.txt"; WriteArrayToFileOrDie(filename, x, A->num_cols()); + StringAppendF(&matlab_script, + "lsqp.x = load('%s', '-ascii');\n", filename.c_str()); } + string matlab_filename = filename_prefix + ".m"; + WriteStringToFileOrDie(matlab_script, matlab_filename); return true; } diff --git a/extern/libmv/third_party/ceres/internal/ceres/linear_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/linear_solver.cc index b2e3941eea1..08c3ba110d0 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/linear_solver.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/linear_solver.cc @@ -30,13 +30,14 @@ #include "ceres/linear_solver.h" -#include #include "ceres/cgnr_solver.h" +#include "ceres/dense_normal_cholesky_solver.h" #include "ceres/dense_qr_solver.h" #include "ceres/iterative_schur_complement_solver.h" #include "ceres/schur_complement_solver.h" #include "ceres/sparse_normal_cholesky_solver.h" #include "ceres/types.h" +#include "glog/logging.h" namespace ceres { namespace internal { @@ -50,22 +51,24 @@ LinearSolver* LinearSolver::Create(const LinearSolver::Options& options) { return new CgnrSolver(options); case SPARSE_NORMAL_CHOLESKY: -#ifndef CERES_NO_SUITESPARSE - return new SparseNormalCholeskySolver(options); -#else +#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE) LOG(WARNING) << "SPARSE_NORMAL_CHOLESKY is not available. Please " - << "build Ceres with SuiteSparse. Returning NULL."; + << "build Ceres with SuiteSparse or CXSparse. " + << "Returning NULL."; return NULL; -#endif // CERES_NO_SUITESPARSE +#else + return new SparseNormalCholeskySolver(options); +#endif case SPARSE_SCHUR: -#ifndef CERES_NO_SUITESPARSE - return new SparseSchurComplementSolver(options); -#else +#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE) LOG(WARNING) << "SPARSE_SCHUR is not available. Please " - << "build Ceres with SuiteSparse. Returning NULL."; + << "build Ceres with SuiteSparse or CXSparse. " + << "Returning NULL."; return NULL; -#endif // CERES_NO_SUITESPARSE +#else + return new SparseSchurComplementSolver(options); +#endif case DENSE_SCHUR: return new DenseSchurComplementSolver(options); @@ -76,10 +79,13 @@ LinearSolver* LinearSolver::Create(const LinearSolver::Options& options) { case DENSE_QR: return new DenseQRSolver(options); + case DENSE_NORMAL_CHOLESKY: + return new DenseNormalCholeskySolver(options); + default: LOG(FATAL) << "Unknown linear solver type :" << options.type; - return NULL; // MSVC doesn't understand that LOG(FATAL) never returns. + return NULL; // MSVC doesn't understand that LOG(FATAL) never returns. } } diff --git a/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h b/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h index 5860ecc8a77..31f88740b9f 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h +++ b/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h @@ -55,10 +55,11 @@ class LinearOperator; // Ax = b // // It is expected that a single instance of a LinearSolver object -// maybe used multiple times for solving different linear -// systems. This allows them to cache and reuse information across -// solves if for example the sparsity of the linear system remains -// constant. +// maybe used multiple times for solving multiple linear systems with +// the same sparsity structure. This allows them to cache and reuse +// information across solves. This means that calling Solve on the +// same LinearSolver instance with two different linear systems will +// result in undefined behaviour. // // Subclasses of LinearSolver use two structs to configure themselves. // The Options struct configures the LinearSolver object for its @@ -70,10 +71,11 @@ class LinearSolver { Options() : type(SPARSE_NORMAL_CHOLESKY), preconditioner_type(JACOBI), + sparse_linear_algebra_library(SUITE_SPARSE), + use_block_amd(true), min_num_iterations(1), max_num_iterations(1), num_threads(1), - constant_sparsity(false), num_eliminate_blocks(0), residual_reset_period(10), row_block_size(Dynamic), @@ -85,6 +87,11 @@ class LinearSolver { PreconditionerType preconditioner_type; + SparseLinearAlgebraLibraryType sparse_linear_algebra_library; + + // See solver.h for explanation of this option. + bool use_block_amd; + // Number of internal iterations that the solver uses. This // parameter only makes sense for iterative solvers like CG. int min_num_iterations; @@ -93,10 +100,6 @@ class LinearSolver { // If possible, how many threads can the solver use. int num_threads; - // If possible cache and reuse the symbolic factorization across - // multiple calls. - bool constant_sparsity; - // Eliminate 0 to num_eliminate_blocks - 1 from the Normal // equations to form a schur complement. Only used by the Schur // complement based solver. The most common use for this parameter @@ -121,8 +124,8 @@ class LinearSolver { // It is expected that these parameters are set programmatically // rather than manually. // - // Please see explicit_schur_complement_solver_impl.h for more - // details. + // Please see schur_complement_solver.h and schur_eliminator.h for + // more details. int row_block_size; int e_block_size; int f_block_size; @@ -244,6 +247,7 @@ class LinearSolver { const PerSolveOptions& per_solve_options, double* x) = 0; + // Factory static LinearSolver* Create(const Options& options); }; diff --git a/extern/libmv/third_party/ceres/internal/ceres/local_parameterization.cc b/extern/libmv/third_party/ceres/internal/ceres/local_parameterization.cc index eeae74e3f95..26e7f4908a4 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/local_parameterization.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/local_parameterization.cc @@ -28,10 +28,11 @@ // // Author: sameeragarwal@google.com (Sameer Agarwal) -#include -#include "ceres/internal/eigen.h" #include "ceres/local_parameterization.h" + +#include "ceres/internal/eigen.h" #include "ceres/rotation.h" +#include "glog/logging.h" namespace ceres { diff --git a/extern/libmv/third_party/ceres/internal/ceres/loss_function.cc b/extern/libmv/third_party/ceres/internal/ceres/loss_function.cc index 00b2b184729..b948f289f21 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/loss_function.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/loss_function.cc @@ -77,6 +77,70 @@ void CauchyLoss::Evaluate(double s, double rho[3]) const { rho[2] = - c_ * (inv * inv); } +void ArctanLoss::Evaluate(double s, double rho[3]) const { + const double sum = 1 + s * s * b_; + const double inv = 1 / sum; + // 'sum' and 'inv' are always positive. + rho[0] = a_ * atan2(s, a_); + rho[1] = inv; + rho[2] = -2 * s * b_ * (inv * inv); +} + +TolerantLoss::TolerantLoss(double a, double b) + : a_(a), + b_(b), + c_(b * log(1.0 + exp(-a / b))) { + CHECK_GE(a, 0.0); + CHECK_GT(b, 0.0); +} + +void TolerantLoss::Evaluate(double s, double rho[3]) const { + const double x = (s - a_) / b_; + // The basic equation is rho[0] = b ln(1 + e^x). However, if e^x is too + // large, it will overflow. Since numerically 1 + e^x == e^x when the + // x is greater than about ln(2^53) for doubles, beyond this threshold + // we substitute x for ln(1 + e^x) as a numerically equivalent approximation. + static const double kLog2Pow53 = 36.7; // ln(MathLimits::kEpsilon). + if (x > kLog2Pow53) { + rho[0] = s - a_ - c_; + rho[1] = 1.0; + rho[2] = 0.0; + } else { + const double e_x = exp(x); + rho[0] = b_ * log(1.0 + e_x) - c_; + rho[1] = e_x / (1.0 + e_x); + rho[2] = 0.5 / (b_ * (1.0 + cosh(x))); + } +} + +ComposedLoss::ComposedLoss(const LossFunction* f, Ownership ownership_f, + const LossFunction* g, Ownership ownership_g) + : f_(CHECK_NOTNULL(f)), + g_(CHECK_NOTNULL(g)), + ownership_f_(ownership_f), + ownership_g_(ownership_g) { +} + +ComposedLoss::~ComposedLoss() { + if (ownership_f_ == DO_NOT_TAKE_OWNERSHIP) { + f_.release(); + } + if (ownership_g_ == DO_NOT_TAKE_OWNERSHIP) { + g_.release(); + } +} + +void ComposedLoss::Evaluate(double s, double rho[3]) const { + double rho_f[3], rho_g[3]; + g_->Evaluate(s, rho_g); + f_->Evaluate(rho_g[0], rho_f); + rho[0] = rho_f[0]; + // f'(g(s)) * g'(s). + rho[1] = rho_f[1] * rho_g[1]; + // f''(g(s)) * g'(s) * g'(s) + f'(g(s)) * g''(s). + rho[2] = rho_f[2] * rho_g[1] * rho_g[1] + rho_f[1] * rho_g[2]; +} + void ScaledLoss::Evaluate(double s, double rho[3]) const { if (rho_.get() == NULL) { rho[0] = a_ * s; diff --git a/extern/libmv/third_party/ceres/internal/ceres/matrix_proto.h b/extern/libmv/third_party/ceres/internal/ceres/matrix_proto.h index b8a3a1a6de6..94b3076e3d7 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/matrix_proto.h +++ b/extern/libmv/third_party/ceres/internal/ceres/matrix_proto.h @@ -33,7 +33,7 @@ #ifndef CERES_INTERNAL_MATRIX_PROTO_H_ #define CERES_INTERNAL_MATRIX_PROTO_H_ -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS #include "ceres/matrix.pb.h" #endif diff --git a/extern/libmv/third_party/ceres/internal/ceres/minimizer.h b/extern/libmv/third_party/ceres/internal/ceres/minimizer.h index 77cb00cb6b4..cfc98a3ebd0 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/minimizer.h +++ b/extern/libmv/third_party/ceres/internal/ceres/minimizer.h @@ -40,6 +40,8 @@ namespace internal { class Evaluator; class LinearSolver; +class SparseMatrix; +class TrustRegionStrategy; // Interface for non-linear least squares solvers. class Minimizer { @@ -48,53 +50,93 @@ class Minimizer { // see solver.h for detailed information about the meaning and // default values of each of these parameters. struct Options { + Options() { + Init(Solver::Options()); + } + explicit Options(const Solver::Options& options) { + Init(options); + } + + void Init(const Solver::Options& options) { max_num_iterations = options.max_num_iterations; - max_solver_time_sec = options.max_solver_time_sec; + max_solver_time_in_seconds = options.max_solver_time_in_seconds; + max_step_solver_retries = 5; gradient_tolerance = options.gradient_tolerance; parameter_tolerance = options.parameter_tolerance; function_tolerance = options.function_tolerance; min_relative_decrease = options.min_relative_decrease; eta = options.eta; - tau = options.tau; jacobi_scaling = options.jacobi_scaling; - crash_and_dump_lsqp_on_failure = options.crash_and_dump_lsqp_on_failure; + use_nonmonotonic_steps = options.use_nonmonotonic_steps; + max_consecutive_nonmonotonic_steps = + options.max_consecutive_nonmonotonic_steps; lsqp_dump_directory = options.lsqp_dump_directory; lsqp_iterations_to_dump = options.lsqp_iterations_to_dump; lsqp_dump_format_type = options.lsqp_dump_format_type; num_eliminate_blocks = options.num_eliminate_blocks; - logging_type = options.logging_type; + max_num_consecutive_invalid_steps = + options.max_num_consecutive_invalid_steps; + min_trust_region_radius = options.min_trust_region_radius; + evaluator = NULL; + trust_region_strategy = NULL; + jacobian = NULL; + callbacks = options.callbacks; } int max_num_iterations; - int max_solver_time_sec; + double max_solver_time_in_seconds; + + // Number of times the linear solver should be retried in case of + // numerical failure. The retries are done by exponentially scaling up + // mu at each retry. This leads to stronger and stronger + // regularization making the linear least squares problem better + // conditioned at each retry. + int max_step_solver_retries; double gradient_tolerance; double parameter_tolerance; double function_tolerance; double min_relative_decrease; double eta; - double tau; bool jacobi_scaling; - bool crash_and_dump_lsqp_on_failure; + bool use_nonmonotonic_steps; + int max_consecutive_nonmonotonic_steps; vector lsqp_iterations_to_dump; DumpFormatType lsqp_dump_format_type; string lsqp_dump_directory; int num_eliminate_blocks; - LoggingType logging_type; + int max_num_consecutive_invalid_steps; + int min_trust_region_radius; // List of callbacks that are executed by the Minimizer at the end // of each iteration. // - // Client owns these pointers. + // The Options struct does not own these pointers. vector callbacks; + + // Object responsible for evaluating the cost, residuals and + // Jacobian matrix. The Options struct does not own this pointer. + Evaluator* evaluator; + + // Object responsible for actually computing the trust region + // step, and sizing the trust region radius. The Options struct + // does not own this pointer. + TrustRegionStrategy* trust_region_strategy; + + // Object holding the Jacobian matrix. It is assumed that the + // sparsity structure of the matrix has already been initialized + // and will remain constant for the life time of the + // optimization. The Options struct does not own this pointer. + SparseMatrix* jacobian; }; virtual ~Minimizer() {} + + // Note: The minimizer is expected to update the state of the + // parameters array every iteration. This is required for the + // StateUpdatingCallback to work. virtual void Minimize(const Options& options, - Evaluator* evaluator, - LinearSolver* linear_solver, - const double* initial_parameters, - double* final_parameters, + double* parameters, Solver::Summary* summary) = 0; }; diff --git a/extern/libmv/third_party/ceres/internal/ceres/mutex.h b/extern/libmv/third_party/ceres/internal/ceres/mutex.h index 6514b107041..5090a71b78d 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/mutex.h +++ b/extern/libmv/third_party/ceres/internal/ceres/mutex.h @@ -95,11 +95,11 @@ #ifndef CERES_INTERNAL_MUTEX_H_ #define CERES_INTERNAL_MUTEX_H_ -#if defined(NO_THREADS) +#if defined(CERES_NO_THREADS) typedef int MutexType; // to keep a lock-count #elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__) -# define WIN32_LEAN_AND_MEAN // We only need minimal includes -# ifdef GMUTEX_TRYLOCK +# define CERES_WIN32_LEAN_AND_MEAN // We only need minimal includes +# ifdef CERES_GMUTEX_TRYLOCK // We need Windows NT or later for TryEnterCriticalSection(). If you // don't need that functionality, you can remove these _WIN32_WINNT // lines, and change TryLock() to assert(0) or something. @@ -108,9 +108,9 @@ # endif # endif // To avoid macro definition of ERROR. -# define NOGDI +# define CERES_NOGDI // To avoid macro definition of min/max. -# define NOMINMAX +# define CERES_NOMINMAX # include typedef CRITICAL_SECTION MutexType; #elif defined(CERES_HAVE_PTHREAD) && defined(CERES_HAVE_RWLOCK) @@ -151,7 +151,7 @@ class Mutex { inline void Lock(); // Block if needed until free then acquire exclusively inline void Unlock(); // Release a lock acquired via Lock() -#ifdef GMUTEX_TRYLOCK +#ifdef CERES_GMUTEX_TRYLOCK inline bool TryLock(); // If free, Lock() and return true, else return false #endif // Note that on systems that don't support read-write locks, these may @@ -183,7 +183,7 @@ class Mutex { }; // Now the implementation of Mutex for various systems -#if defined(NO_THREADS) +#if defined(CERES_NO_THREADS) // When we don't have threads, we can be either reading or writing, // but not both. We can have lots of readers at once (in no-threads @@ -199,7 +199,7 @@ Mutex::Mutex() : mutex_(0) { } Mutex::~Mutex() { assert(mutex_ == 0); } void Mutex::Lock() { assert(--mutex_ == -1); } void Mutex::Unlock() { assert(mutex_++ == -1); } -#ifdef GMUTEX_TRYLOCK +#ifdef CERES_GMUTEX_TRYLOCK bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; } #endif void Mutex::ReaderLock() { assert(++mutex_ > 0); } @@ -220,91 +220,101 @@ void Mutex::ReaderUnlock() { Unlock(); } #elif defined(CERES_HAVE_PTHREAD) && defined(CERES_HAVE_RWLOCK) -#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \ - if (is_safe_ && fncall(&mutex_) != 0) abort(); \ +#define CERES_SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \ + if (is_safe_ && fncall(&mutex_) != 0) abort(); \ } while (0) Mutex::Mutex() { SetIsSafe(); if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort(); } -Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy); } -void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); } -void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); } -#ifdef GMUTEX_TRYLOCK +Mutex::~Mutex() { CERES_SAFE_PTHREAD(pthread_rwlock_destroy); } +void Mutex::Lock() { CERES_SAFE_PTHREAD(pthread_rwlock_wrlock); } +void Mutex::Unlock() { CERES_SAFE_PTHREAD(pthread_rwlock_unlock); } +#ifdef CERES_GMUTEX_TRYLOCK bool Mutex::TryLock() { return is_safe_ ? pthread_rwlock_trywrlock(&mutex_) == 0 : true; } #endif -void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); } -void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); } -#undef SAFE_PTHREAD +void Mutex::ReaderLock() { CERES_SAFE_PTHREAD(pthread_rwlock_rdlock); } +void Mutex::ReaderUnlock() { CERES_SAFE_PTHREAD(pthread_rwlock_unlock); } +#undef CERES_SAFE_PTHREAD #elif defined(CERES_HAVE_PTHREAD) -#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \ - if (is_safe_ && fncall(&mutex_) != 0) abort(); \ +#define CERES_SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \ + if (is_safe_ && fncall(&mutex_) != 0) abort(); \ } while (0) Mutex::Mutex() { SetIsSafe(); if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort(); } -Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy); } -void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); } -void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); } -#ifdef GMUTEX_TRYLOCK +Mutex::~Mutex() { CERES_SAFE_PTHREAD(pthread_mutex_destroy); } +void Mutex::Lock() { CERES_SAFE_PTHREAD(pthread_mutex_lock); } +void Mutex::Unlock() { CERES_SAFE_PTHREAD(pthread_mutex_unlock); } +#ifdef CERES_GMUTEX_TRYLOCK bool Mutex::TryLock() { return is_safe_ ? pthread_mutex_trylock(&mutex_) == 0 : true; } #endif void Mutex::ReaderLock() { Lock(); } void Mutex::ReaderUnlock() { Unlock(); } -#undef SAFE_PTHREAD +#undef CERES_SAFE_PTHREAD #endif // -------------------------------------------------------------------------- // Some helper classes -// MutexLock(mu) acquires mu when constructed and releases it when destroyed. -class MutexLock { +// Note: The weird "Ceres" prefix for the class is a workaround for having two +// similar mutex.h files included in the same translation unit. This is a +// problem because macros do not respect C++ namespaces, and as a result, this +// does not work well (e.g. inside Chrome). The offending macros are +// "MutexLock(x) COMPILE_ASSERT(false)". To work around this, "Ceres" is +// prefixed to the class names; this permits defining the classes. + +// CeresMutexLock(mu) acquires mu when constructed and releases it when destroyed. +class CeresMutexLock { public: - explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); } - ~MutexLock() { mu_->Unlock(); } + explicit CeresMutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); } + ~CeresMutexLock() { mu_->Unlock(); } private: Mutex * const mu_; // Disallow "evil" constructors - MutexLock(const MutexLock&); - void operator=(const MutexLock&); + CeresMutexLock(const CeresMutexLock&); + void operator=(const CeresMutexLock&); }; -// ReaderMutexLock and WriterMutexLock do the same, for rwlocks -class ReaderMutexLock { +// CeresReaderMutexLock and CeresWriterMutexLock do the same, for rwlocks +class CeresReaderMutexLock { public: - explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); } - ~ReaderMutexLock() { mu_->ReaderUnlock(); } + explicit CeresReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); } + ~CeresReaderMutexLock() { mu_->ReaderUnlock(); } private: Mutex * const mu_; // Disallow "evil" constructors - ReaderMutexLock(const ReaderMutexLock&); - void operator=(const ReaderMutexLock&); + CeresReaderMutexLock(const CeresReaderMutexLock&); + void operator=(const CeresReaderMutexLock&); }; -class WriterMutexLock { +class CeresWriterMutexLock { public: - explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); } - ~WriterMutexLock() { mu_->WriterUnlock(); } + explicit CeresWriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); } + ~CeresWriterMutexLock() { mu_->WriterUnlock(); } private: Mutex * const mu_; // Disallow "evil" constructors - WriterMutexLock(const WriterMutexLock&); - void operator=(const WriterMutexLock&); + CeresWriterMutexLock(const CeresWriterMutexLock&); + void operator=(const CeresWriterMutexLock&); }; // Catch bug where variable name is omitted, e.g. MutexLock (&mu); -#define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name) -#define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name) -#define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name) +#define CeresMutexLock(x) \ + COMPILE_ASSERT(0, ceres_mutex_lock_decl_missing_var_name) +#define CeresReaderMutexLock(x) \ + COMPILE_ASSERT(0, ceres_rmutex_lock_decl_missing_var_name) +#define CeresWriterMutexLock(x) \ + COMPILE_ASSERT(0, ceres_wmutex_lock_decl_missing_var_name) } // namespace internal } // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/normal_prior.cc b/extern/libmv/third_party/ceres/internal/ceres/normal_prior.cc index f30bbc8b46b..392d728fb32 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/normal_prior.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/normal_prior.cc @@ -32,11 +32,10 @@ #include #include - -#include #include "ceres/internal/eigen.h" #include "ceres/internal/scoped_ptr.h" #include "ceres/types.h" +#include "glog/logging.h" namespace ceres { diff --git a/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h b/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h index 4bac1a85828..f20805ca873 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h +++ b/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h @@ -32,13 +32,15 @@ #define CERES_INTERNAL_PARAMETER_BLOCK_H_ #include +#include +#include "ceres/array_utils.h" #include "ceres/integral_types.h" -#include #include "ceres/internal/eigen.h" #include "ceres/internal/port.h" #include "ceres/internal/scoped_ptr.h" #include "ceres/local_parameterization.h" -#include "ceres/residual_block_utils.h" +#include "ceres/stringprintf.h" +#include "glog/logging.h" namespace ceres { namespace internal { @@ -172,6 +174,19 @@ class ParameterBlock { return local_parameterization_->Plus(x, delta, x_plus_delta); } + string ToString() const { + return StringPrintf("{ user_state=%p, state=%p, size=%d, " + "constant=%d, index=%d, state_offset=%d, " + "delta_offset=%d }", + user_state_, + state_, + size_, + is_constant_, + index_, + state_offset_, + delta_offset_); + } + private: void Init(double* user_state, int size, diff --git a/extern/libmv/third_party/ceres/internal/ceres/partitioned_matrix_view.cc b/extern/libmv/third_party/ceres/internal/ceres/partitioned_matrix_view.cc index fcf8fd53aed..0722fc82c02 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/partitioned_matrix_view.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/partitioned_matrix_view.cc @@ -35,10 +35,10 @@ #include #include #include -#include #include "ceres/block_sparse_matrix.h" #include "ceres/block_structure.h" #include "ceres/internal/eigen.h" +#include "glog/logging.h" namespace ceres { namespace internal { diff --git a/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.cc new file mode 100644 index 00000000000..20c01566a89 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.cc @@ -0,0 +1,184 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: moll.markus@arcor.de (Markus Moll) + +#include "ceres/polynomial_solver.h" + +#include +#include +#include "Eigen/Dense" +#include "ceres/internal/port.h" +#include "glog/logging.h" + +namespace ceres { +namespace internal { +namespace { + +// Balancing function as described by B. N. Parlett and C. Reinsch, +// "Balancing a Matrix for Calculation of Eigenvalues and Eigenvectors". +// In: Numerische Mathematik, Volume 13, Number 4 (1969), 293-304, +// Springer Berlin / Heidelberg. DOI: 10.1007/BF02165404 +void BalanceCompanionMatrix(Matrix* companion_matrix_ptr) { + CHECK_NOTNULL(companion_matrix_ptr); + Matrix& companion_matrix = *companion_matrix_ptr; + Matrix companion_matrix_offdiagonal = companion_matrix; + companion_matrix_offdiagonal.diagonal().setZero(); + + const int degree = companion_matrix.rows(); + + // gamma <= 1 controls how much a change in the scaling has to + // lower the 1-norm of the companion matrix to be accepted. + // + // gamma = 1 seems to lead to cycles (numerical issues?), so + // we set it slightly lower. + const double gamma = 0.9; + + // Greedily scale row/column pairs until there is no change. + bool scaling_has_changed; + do { + scaling_has_changed = false; + + for (int i = 0; i < degree; ++i) { + const double row_norm = companion_matrix_offdiagonal.row(i).lpNorm<1>(); + const double col_norm = companion_matrix_offdiagonal.col(i).lpNorm<1>(); + + // Decompose row_norm/col_norm into mantissa * 2^exponent, + // where 0.5 <= mantissa < 1. Discard mantissa (return value + // of frexp), as only the exponent is needed. + int exponent = 0; + std::frexp(row_norm / col_norm, &exponent); + exponent /= 2; + + if (exponent != 0) { + const double scaled_col_norm = std::ldexp(col_norm, exponent); + const double scaled_row_norm = std::ldexp(row_norm, -exponent); + if (scaled_col_norm + scaled_row_norm < gamma * (col_norm + row_norm)) { + // Accept the new scaling. (Multiplication by powers of 2 should not + // introduce rounding errors (ignoring non-normalized numbers and + // over- or underflow)) + scaling_has_changed = true; + companion_matrix_offdiagonal.row(i) *= std::ldexp(1.0, -exponent); + companion_matrix_offdiagonal.col(i) *= std::ldexp(1.0, exponent); + } + } + } + } while (scaling_has_changed); + + companion_matrix_offdiagonal.diagonal() = companion_matrix.diagonal(); + companion_matrix = companion_matrix_offdiagonal; + VLOG(3) << "Balanced companion matrix is\n" << companion_matrix; +} + +void BuildCompanionMatrix(const Vector& polynomial, + Matrix* companion_matrix_ptr) { + CHECK_NOTNULL(companion_matrix_ptr); + Matrix& companion_matrix = *companion_matrix_ptr; + + const int degree = polynomial.size() - 1; + + companion_matrix.resize(degree, degree); + companion_matrix.setZero(); + companion_matrix.diagonal(-1).setOnes(); + companion_matrix.col(degree - 1) = -polynomial.reverse().head(degree); +} + +// Remove leading terms with zero coefficients. +Vector RemoveLeadingZeros(const Vector& polynomial_in) { + int i = 0; + while (i < (polynomial_in.size() - 1) && polynomial_in(i) == 0.0) { + ++i; + } + return polynomial_in.tail(polynomial_in.size() - i); +} +} // namespace + +bool FindPolynomialRoots(const Vector& polynomial_in, + Vector* real, + Vector* imaginary) { + if (polynomial_in.size() == 0) { + LOG(ERROR) << "Invalid polynomial of size 0 passed to FindPolynomialRoots"; + return false; + } + + Vector polynomial = RemoveLeadingZeros(polynomial_in); + const int degree = polynomial.size() - 1; + + // Is the polynomial constant? + if (degree == 0) { + LOG(WARNING) << "Trying to extract roots from a constant " + << "polynomial in FindPolynomialRoots"; + return true; + } + + // Divide by leading term + const double leading_term = polynomial(0); + polynomial /= leading_term; + + // Separately handle linear polynomials. + if (degree == 1) { + if (real != NULL) { + real->resize(1); + (*real)(0) = -polynomial(1); + } + if (imaginary != NULL) { + imaginary->resize(1); + imaginary->setZero(); + } + } + + // The degree is now known to be at least 2. + // Build and balance the companion matrix to the polynomial. + Matrix companion_matrix(degree, degree); + BuildCompanionMatrix(polynomial, &companion_matrix); + BalanceCompanionMatrix(&companion_matrix); + + // Find its (complex) eigenvalues. + Eigen::EigenSolver solver(companion_matrix, + Eigen::EigenvaluesOnly); + if (solver.info() != Eigen::Success) { + LOG(ERROR) << "Failed to extract eigenvalues from companion matrix."; + return false; + } + + // Output roots + if (real != NULL) { + *real = solver.eigenvalues().real(); + } else { + LOG(WARNING) << "NULL pointer passed as real argument to " + << "FindPolynomialRoots. Real parts of the roots will not " + << "be returned."; + } + if (imaginary != NULL) { + *imaginary = solver.eigenvalues().imag(); + } + return true; +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.h b/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.h new file mode 100644 index 00000000000..1cf07ddb549 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.h @@ -0,0 +1,65 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: moll.markus@arcor.de (Markus Moll) + +#ifndef CERES_INTERNAL_POLYNOMIAL_SOLVER_H_ +#define CERES_INTERNAL_POLYNOMIAL_SOLVER_H_ + +#include "ceres/internal/eigen.h" + +namespace ceres { +namespace internal { + +// Use the companion matrix eigenvalues to determine the roots of the polynomial +// +// sum_{i=0}^N polynomial(i) x^{N-i}. +// +// This function returns true on success, false otherwise. +// Failure indicates that the polynomial is invalid (of size 0) or +// that the eigenvalues of the companion matrix could not be computed. +// On failure, a more detailed message will be written to LOG(ERROR). +// If real is not NULL, the real parts of the roots will be returned in it. +// Likewise, if imaginary is not NULL, imaginary parts will be returned in it. +bool FindPolynomialRoots(const Vector& polynomial, + Vector* real, + Vector* imaginary); + +// Evaluate the polynomial at x using the Horner scheme. +inline double EvaluatePolynomial(const Vector& polynomial, double x) { + double v = 0.0; + for (int i = 0; i < polynomial.size(); ++i) { + v = v * x + polynomial(i); + } + return v; +} + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_POLYNOMIAL_SOLVER_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc index 68242477d6f..c186f527be8 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc @@ -37,16 +37,15 @@ #include #include #include - -#include +#include "ceres/cost_function.h" +#include "ceres/loss_function.h" +#include "ceres/map_util.h" #include "ceres/parameter_block.h" #include "ceres/program.h" #include "ceres/residual_block.h" #include "ceres/stl_util.h" -#include "ceres/map_util.h" #include "ceres/stringprintf.h" -#include "ceres/cost_function.h" -#include "ceres/loss_function.h" +#include "glog/logging.h" namespace ceres { namespace internal { diff --git a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h index 523860e652a..2ca055448c3 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h +++ b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h @@ -118,7 +118,7 @@ class ProblemImpl { map parameter_block_map_; internal::scoped_ptr program_; - DISALLOW_COPY_AND_ASSIGN(ProblemImpl); + CERES_DISALLOW_COPY_AND_ASSIGN(ProblemImpl); }; } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/program.cc b/extern/libmv/third_party/ceres/internal/ceres/program.cc index 444b1020253..82d76d39233 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/program.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/program.cc @@ -32,14 +32,18 @@ #include #include +#include "ceres/casts.h" +#include "ceres/compressed_row_sparse_matrix.h" +#include "ceres/cost_function.h" +#include "ceres/evaluator.h" +#include "ceres/internal/port.h" +#include "ceres/local_parameterization.h" +#include "ceres/loss_function.h" +#include "ceres/map_util.h" #include "ceres/parameter_block.h" +#include "ceres/problem.h" #include "ceres/residual_block.h" #include "ceres/stl_util.h" -#include "ceres/map_util.h" -#include "ceres/problem.h" -#include "ceres/cost_function.h" -#include "ceres/loss_function.h" -#include "ceres/local_parameterization.h" namespace ceres { namespace internal { @@ -69,7 +73,8 @@ vector* Program::mutable_residual_blocks() { bool Program::StateVectorToParameterBlocks(const double *state) { for (int i = 0; i < parameter_blocks_.size(); ++i) { - if (!parameter_blocks_[i]->SetState(state)) { + if (!parameter_blocks_[i]->IsConstant() && + !parameter_blocks_[i]->SetState(state)) { return false; } state += parameter_blocks_[i]->Size(); @@ -86,9 +91,18 @@ void Program::ParameterBlocksToStateVector(double *state) const { void Program::CopyParameterBlockStateToUserState() { for (int i = 0; i < parameter_blocks_.size(); ++i) { - parameter_blocks_[i]->GetState( - parameter_blocks_[i]->mutable_user_state()); + parameter_blocks_[i]->GetState(parameter_blocks_[i]->mutable_user_state()); + } +} + +bool Program::SetParameterBlockStatePtrsToUserStatePtrs() { + for (int i = 0; i < parameter_blocks_.size(); ++i) { + if (!parameter_blocks_[i]->IsConstant() && + !parameter_blocks_[i]->SetState(parameter_blocks_[i]->user_state())) { + return false; + } } + return true; } bool Program::Plus(const double* state, @@ -193,40 +207,25 @@ int Program::MaxParametersPerResidualBlock() const { return max_parameters; } -bool Program::Evaluate(double* cost, double* residuals) { - *cost = 0.0; - - // Scratch space is only needed if residuals is NULL. - scoped_array scratch; - if (residuals == NULL) { - scratch.reset(new double[MaxScratchDoublesNeededForEvaluate()]); - } else { - // TODO(keir): Is this needed? Check by removing the equivalent statement in - // dense_evaluator.cc and running the tests. - VectorRef(residuals, NumResiduals()).setZero(); - } - +int Program::MaxResidualsPerResidualBlock() const { + int max_residuals = 0; for (int i = 0; i < residual_blocks_.size(); ++i) { - ResidualBlock* residual_block = residual_blocks_[i]; - - // Evaluate the cost function for this residual. - double residual_cost; - if (!residual_block->Evaluate(&residual_cost, - residuals, - NULL, // No jacobian. - scratch.get())) { - return false; - } - - // Accumulate residual cost into the total cost. - *cost += residual_cost; + max_residuals = max(max_residuals, + residual_blocks_[i]->NumResiduals()); + } + return max_residuals; +} - // Update the residuals cursor. - if (residuals != NULL) { - residuals += residual_block->NumResiduals(); - } +string Program::ToString() const { + string ret = "Program dump\n"; + ret += StringPrintf("Number of parameter blocks: %d\n", NumParameterBlocks()); + ret += StringPrintf("Number of parameters: %d\n", NumParameters()); + ret += "Parameters:\n"; + for (int i = 0; i < parameter_blocks_.size(); ++i) { + ret += StringPrintf("%d: %s\n", + i, parameter_blocks_[i]->ToString().c_str()); } - return true; + return ret; } } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/program.h b/extern/libmv/third_party/ceres/internal/ceres/program.h index 113d352d562..5002b7e752e 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/program.h +++ b/extern/libmv/third_party/ceres/internal/ceres/program.h @@ -31,6 +31,7 @@ #ifndef CERES_INTERNAL_PROGRAM_H_ #define CERES_INTERNAL_PROGRAM_H_ +#include #include #include "ceres/internal/port.h" @@ -71,9 +72,14 @@ class Program { bool StateVectorToParameterBlocks(const double *state); void ParameterBlocksToStateVector(double *state) const; - // Copy internal state out to the user's parameters. + // Copy internal state to the user's parameters. void CopyParameterBlockStateToUserState(); + // Set the parameter block pointers to the user pointers. Since this + // runs parameter block set state internally, which may call local + // parameterizations, this can fail. False is returned on failure. + bool SetParameterBlockStatePtrsToUserStatePtrs(); + // Update a state vector for the program given a delta. bool Plus(const double* state, const double* delta, @@ -103,16 +109,11 @@ class Program { int MaxScratchDoublesNeededForEvaluate() const; int MaxDerivativesPerResidualBlock() const; int MaxParametersPerResidualBlock() const; + int MaxResidualsPerResidualBlock() const; - // Evaluate the cost and maybe the residuals for the program. If residuals is - // NULL, then residuals are not calculated. If the jacobian is needed, instead - // use the various evaluators (e.g. dense_evaluator.h). - // - // This is a trivial implementation of evaluate not intended for use in the - // core solving loop. The other evaluators, which support constructing the - // jacobian in addition to the cost and residuals, are considerably - // complicated by the need to construct the jacobian. - bool Evaluate(double* cost, double* residuals); + // A human-readable dump of the parameter blocks for debugging. + // TODO(keir): If necessary, also dump the residual blocks. + string ToString() const; private: // The Program does not own the ParameterBlock or ResidualBlock objects. diff --git a/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h b/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h index 7ec74b1b269..6c48e7d7643 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h +++ b/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h @@ -120,13 +120,18 @@ class ProgramEvaluator : public Evaluator { bool Evaluate(const double* state, double* cost, double* residuals, + double* gradient, SparseMatrix* jacobian) { // The parameters are stateful, so set the state before evaluating. if (!program_->StateVectorToParameterBlocks(state)) { return false; } - if (jacobian) { + if (residuals != NULL) { + VectorRef(residuals, program_->NumResiduals()).setZero(); + } + + if (jacobian != NULL) { jacobian->SetZero(); } @@ -158,13 +163,16 @@ class ProgramEvaluator : public Evaluator { // Prepare block residuals if requested. const ResidualBlock* residual_block = program_->residual_blocks()[i]; - double* block_residuals = (residuals != NULL) - ? (residuals + residual_layout_[i]) - : NULL; + double* block_residuals = NULL; + if (residuals != NULL) { + block_residuals = residuals + residual_layout_[i]; + } else if (gradient != NULL) { + block_residuals = scratch->residual_block_residuals.get(); + } // Prepare block jacobians if requested. double** block_jacobians = NULL; - if (jacobian != NULL) { + if (jacobian != NULL || gradient != NULL) { preparer->Prepare(residual_block, i, jacobian, @@ -174,10 +182,11 @@ class ProgramEvaluator : public Evaluator { // Evaluate the cost, residuals, and jacobians. double block_cost; - if (!residual_block->Evaluate(&block_cost, - block_residuals, - block_jacobians, - scratch->scratch.get())) { + if (!residual_block->Evaluate( + &block_cost, + block_residuals, + block_jacobians, + scratch->residual_block_evaluate_scratch.get())) { abort = true; // This ensures that the OpenMP threads have a consistent view of 'abort'. Do // the flush inside the failure case so that there is usually only one @@ -188,19 +197,49 @@ class ProgramEvaluator : public Evaluator { scratch->cost += block_cost; + // Store the jacobians, if they were requested. if (jacobian != NULL) { jacobian_writer_.Write(i, residual_layout_[i], block_jacobians, jacobian); } + + // Compute and store the gradient, if it was requested. + if (gradient != NULL) { + int num_residuals = residual_block->NumResiduals(); + int num_parameter_blocks = residual_block->NumParameterBlocks(); + for (int j = 0; j < num_parameter_blocks; ++j) { + const ParameterBlock* parameter_block = + residual_block->parameter_blocks()[j]; + if (parameter_block->IsConstant()) { + continue; + } + MatrixRef block_jacobian(block_jacobians[j], + num_residuals, + parameter_block->LocalSize()); + VectorRef block_gradient(scratch->gradient.get() + + parameter_block->delta_offset(), + parameter_block->LocalSize()); + VectorRef block_residual(block_residuals, num_residuals); + block_gradient += block_residual.transpose() * block_jacobian; + } + } } if (!abort) { - // Sum the cost from each thread. + // Sum the cost and gradient (if requested) from each thread. (*cost) = 0.0; + int num_parameters = program_->NumEffectiveParameters(); + if (gradient != NULL) { + VectorRef(gradient, num_parameters).setZero(); + } for (int i = 0; i < options_.num_threads; ++i) { (*cost) += evaluate_scratch_[i].cost; + if (gradient != NULL) { + VectorRef(gradient, num_parameters) += + VectorRef(evaluate_scratch_[i].gradient.get(), num_parameters); + } } } return !abort; @@ -224,16 +263,28 @@ class ProgramEvaluator : public Evaluator { } private: + // Per-thread scratch space needed to evaluate and store each residual block. struct EvaluateScratch { void Init(int max_parameters_per_residual_block, - int max_scratch_doubles_needed_for_evaluate) { + int max_scratch_doubles_needed_for_evaluate, + int max_residuals_per_residual_block, + int num_parameters) { + residual_block_evaluate_scratch.reset( + new double[max_scratch_doubles_needed_for_evaluate]); + gradient.reset(new double[num_parameters]); + VectorRef(gradient.get(), num_parameters).setZero(); + residual_block_residuals.reset( + new double[max_residuals_per_residual_block]); jacobian_block_ptrs.reset( new double*[max_parameters_per_residual_block]); - scratch.reset(new double[max_scratch_doubles_needed_for_evaluate]); } double cost; - scoped_array scratch; + scoped_array residual_block_evaluate_scratch; + // The gradient in the local parameterization. + scoped_array gradient; + // Enough space to store the residual for the largest residual block. + scoped_array residual_block_residuals; scoped_array jacobian_block_ptrs; }; @@ -256,11 +307,16 @@ class ProgramEvaluator : public Evaluator { program.MaxParametersPerResidualBlock(); int max_scratch_doubles_needed_for_evaluate = program.MaxScratchDoublesNeededForEvaluate(); + int max_residuals_per_residual_block = + program.MaxResidualsPerResidualBlock(); + int num_parameters = program.NumEffectiveParameters(); EvaluateScratch* evaluate_scratch = new EvaluateScratch[num_threads]; for (int i = 0; i < num_threads; i++) { evaluate_scratch[i].Init(max_parameters_per_residual_block, - max_scratch_doubles_needed_for_evaluate); + max_scratch_doubles_needed_for_evaluate, + max_residuals_per_residual_block, + num_parameters); } return evaluate_scratch; } diff --git a/extern/libmv/third_party/ceres/internal/ceres/random.h b/extern/libmv/third_party/ceres/internal/ceres/random.h index 769e0b4dd27..352c0032b5a 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/random.h +++ b/extern/libmv/third_party/ceres/internal/ceres/random.h @@ -27,21 +27,44 @@ // POSSIBILITY OF SUCH DAMAGE. // // Author: keir@google.com (Keir Mierle) +// sameeragarwal@google.com (Sameer Agarwal) #ifndef CERES_INTERNAL_RANDOM_H_ #define CERES_INTERNAL_RANDOM_H_ +#include +#include +#include "ceres/internal/port.h" + namespace ceres { -inline double RandDouble() { - double r = rand(); - return r / RAND_MAX; +inline void SetRandomState(int state) { + srand(state); } inline int Uniform(int n) { return rand() % n; } +inline double RandDouble() { + double r = static_cast(rand()); + return r / RAND_MAX; +} + +// Box-Muller algorithm for normal random number generation. +// http://en.wikipedia.org/wiki/Box-Muller_transform +inline double RandNormal() { + double x1, x2, w; + do { + x1 = 2.0 * RandDouble() - 1.0; + x2 = 2.0 * RandDouble() - 1.0; + w = x1 * x1 + x2 * x2; + } while ( w >= 1.0 || w == 0.0 ); + + w = sqrt((-2.0 * log(w)) / w); + return x1 * w; +} + } // namespace ceres #endif // CERES_INTERNAL_RANDOM_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc b/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc index 03867891dba..bdb88b1dd97 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc @@ -102,8 +102,11 @@ bool ResidualBlock::Evaluate(double* cost, InvalidateEvaluation(*this, cost, residuals, eval_jacobians); - if (!cost_function_->Evaluate(parameters.get(), residuals, eval_jacobians) || - !IsEvaluationValid(*this, + if (!cost_function_->Evaluate(parameters.get(), residuals, eval_jacobians)) { + return false; + } + + if (!IsEvaluationValid(*this, parameters.get(), cost, residuals, diff --git a/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc b/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc index 28e03130844..9442bb2a1c1 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc @@ -33,46 +33,17 @@ #include #include #include -#include -#include "ceres/residual_block.h" -#include "ceres/parameter_block.h" -#include "ceres/stringprintf.h" +#include "ceres/array_utils.h" #include "ceres/internal/eigen.h" #include "ceres/internal/port.h" - -#ifdef _MSC_VER -# define isfinite _finite -#endif +#include "ceres/parameter_block.h" +#include "ceres/residual_block.h" +#include "ceres/stringprintf.h" +#include "glog/logging.h" namespace ceres { namespace internal { -// It is a near impossibility that user code generates this exact -// value in normal operation, thus we will use it to fill arrays -// before passing them to user code. If on return an element of the -// array still contains this value, we will assume that the user code -// did not write to that memory location. -static const double kImpossibleValue = 1e302; - -bool IsArrayValid(const int size, const double* x) { - if (x != NULL) { - for (int i = 0; i < size; ++i) { - if (!isfinite(x[i]) || (x[i] == kImpossibleValue)) { - return false; - } - } - } - return true; -} - -void InvalidateArray(const int size, double* x) { - if (x != NULL) { - for (int i = 0; i < size; ++i) { - x[i] = kImpossibleValue; - } - } -} - void InvalidateEvaluation(const ResidualBlock& block, double* cost, double* residuals, @@ -92,7 +63,7 @@ void InvalidateEvaluation(const ResidualBlock& block, // Utility routine to print an array of doubles to a string. If the // array pointer is NULL, it is treated as an array of zeros. -void AppendArrayToString(const int size, const double* x, string* result) { +static void AppendArrayToString(const int size, const double* x, string* result) { for (int i = 0; i < size; ++i) { if (x == NULL) { StringAppendF(result, "Not Computed "); diff --git a/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.h b/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.h index 228867cc60c..7051c2112fd 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.h +++ b/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.h @@ -51,15 +51,6 @@ namespace internal { class ResidualBlock; -// Fill the array x with an impossible value that the user code is -// never expected to compute. -void InvalidateArray(int size, double* x); - -// Check if all the entries of the array x are valid, i.e. all the -// values in the array should be finite and none of them should be -// equal to the "impossible" value used by InvalidateArray. -bool IsArrayValid(int size, const double* x); - // Invalidate cost, resdual and jacobian arrays (if not NULL). void InvalidateEvaluation(const ResidualBlock& block, double* cost, diff --git a/extern/libmv/third_party/ceres/internal/ceres/runtime_numeric_diff_cost_function.cc b/extern/libmv/third_party/ceres/internal/ceres/runtime_numeric_diff_cost_function.cc index ac6d8aa279a..7af275c1dd8 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/runtime_numeric_diff_cost_function.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/runtime_numeric_diff_cost_function.cc @@ -35,11 +35,10 @@ #include #include #include - -#include #include "Eigen/Dense" #include "ceres/cost_function.h" #include "ceres/internal/scoped_ptr.h" +#include "glog/logging.h" namespace ceres { namespace internal { diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc index 2bc8cdd6bec..2cbe78d133a 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc @@ -32,7 +32,13 @@ #include #include #include + +#ifndef CERES_NO_CXSPARSE +#include "cs.h" +#endif // CERES_NO_CXSPARSE + #include "Eigen/Dense" +#include "glog/logging.h" #include "ceres/block_random_access_dense_matrix.h" #include "ceres/block_random_access_matrix.h" #include "ceres/block_random_access_sparse_matrix.h" @@ -48,6 +54,7 @@ #include "ceres/internal/scoped_ptr.h" #include "ceres/types.h" + namespace ceres { namespace internal { @@ -57,7 +64,7 @@ LinearSolver::Summary SchurComplementSolver::SolveImpl( const LinearSolver::PerSolveOptions& per_solve_options, double* x) { const time_t start_time = time(NULL); - if (!options_.constant_sparsity || (eliminator_.get() == NULL)) { + if (eliminator_.get() == NULL) { InitStorage(A->block_structure()); DetectStructure(*A->block_structure(), options_.num_eliminate_blocks, @@ -88,11 +95,11 @@ LinearSolver::Summary SchurComplementSolver::SolveImpl( const time_t backsubstitute_time = time(NULL); summary.termination_type = TOLERANCE; - VLOG(2) << "time (sec) total: " << backsubstitute_time - start_time - << " init: " << init_time - start_time - << " eliminate: " << eliminate_time - init_time - << " solve: " << solve_time - eliminate_time - << " backsubstitute: " << backsubstitute_time - solve_time; + VLOG(2) << "time (sec) total: " << (backsubstitute_time - start_time) + << " init: " << (init_time - start_time) + << " eliminate: " << (eliminate_time - init_time) + << " solve: " << (solve_time - eliminate_time) + << " backsubstitute: " << (backsubstitute_time - solve_time); return summary; } @@ -139,18 +146,33 @@ bool DenseSchurComplementSolver::SolveReducedLinearSystem(double* solution) { return true; } -#ifndef CERES_NO_SUITESPARSE + SparseSchurComplementSolver::SparseSchurComplementSolver( const LinearSolver::Options& options) - : SchurComplementSolver(options), - symbolic_factor_(NULL) { + : SchurComplementSolver(options) { +#ifndef CERES_NO_SUITESPARSE + factor_ = NULL; +#endif // CERES_NO_SUITESPARSE + +#ifndef CERES_NO_CXSPARSE + cxsparse_factor_ = NULL; +#endif // CERES_NO_CXSPARSE } SparseSchurComplementSolver::~SparseSchurComplementSolver() { - if (symbolic_factor_ != NULL) { - ss_.Free(symbolic_factor_); - symbolic_factor_ = NULL; +#ifndef CERES_NO_SUITESPARSE + if (factor_ != NULL) { + ss_.Free(factor_); + factor_ = NULL; } +#endif // CERES_NO_SUITESPARSE + +#ifndef CERES_NO_CXSPARSE + if (cxsparse_factor_ != NULL) { + cxsparse_.Free(cxsparse_factor_); + cxsparse_factor_ = NULL; + } +#endif // CERES_NO_CXSPARSE } // Determine the non-zero blocks in the Schur Complement matrix, and @@ -161,13 +183,13 @@ void SparseSchurComplementSolver::InitStorage( const int num_col_blocks = bs->cols.size(); const int num_row_blocks = bs->rows.size(); - vector blocks(num_col_blocks - num_eliminate_blocks, 0); + blocks_.resize(num_col_blocks - num_eliminate_blocks, 0); for (int i = num_eliminate_blocks; i < num_col_blocks; ++i) { - blocks[i - num_eliminate_blocks] = bs->cols[i].size; + blocks_[i - num_eliminate_blocks] = bs->cols[i].size; } set > block_pairs; - for (int i = 0; i < blocks.size(); ++i) { + for (int i = 0; i < blocks_.size(); ++i) { block_pairs.insert(make_pair(i, i)); } @@ -220,15 +242,34 @@ void SparseSchurComplementSolver::InitStorage( } } - set_lhs(new BlockRandomAccessSparseMatrix(blocks, block_pairs)); + set_lhs(new BlockRandomAccessSparseMatrix(blocks_, block_pairs)); set_rhs(new double[lhs()->num_rows()]); } +bool SparseSchurComplementSolver::SolveReducedLinearSystem(double* solution) { + switch (options().sparse_linear_algebra_library) { + case SUITE_SPARSE: + return SolveReducedLinearSystemUsingSuiteSparse(solution); + case CX_SPARSE: + return SolveReducedLinearSystemUsingCXSparse(solution); + default: + LOG(FATAL) << "Unknown sparse linear algebra library : " + << options().sparse_linear_algebra_library; + } + + LOG(FATAL) << "Unknown sparse linear algebra library : " + << options().sparse_linear_algebra_library; + return false; +} + +#ifndef CERES_NO_SUITESPARSE // Solve the system Sx = r, assuming that the matrix S is stored in a // BlockRandomAccessSparseMatrix. The linear system is solved using // CHOLMOD's sparse cholesky factorization routines. -bool SparseSchurComplementSolver::SolveReducedLinearSystem(double* solution) { - // Extract the TripletSparseMatrix that is used for actually storing S. +bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse( + double* solution) { + const time_t start_time = time(NULL); + TripletSparseMatrix* tsm = const_cast( down_cast(lhs())->matrix()); @@ -245,30 +286,38 @@ bool SparseSchurComplementSolver::SolveReducedLinearSystem(double* solution) { // The matrix is symmetric, and the upper triangular part of the // matrix contains the values. cholmod_lhs->stype = 1; + const time_t lhs_time = time(NULL); cholmod_dense* cholmod_rhs = ss_.CreateDenseVector(const_cast(rhs()), num_rows, num_rows); + const time_t rhs_time = time(NULL); // Symbolic factorization is computed if we don't already have one handy. - if (symbolic_factor_ == NULL) { - symbolic_factor_ = ss_.AnalyzeCholesky(cholmod_lhs); + if (factor_ == NULL) { + if (options().use_block_amd) { + factor_ = ss_.BlockAnalyzeCholesky(cholmod_lhs, blocks_, blocks_); + } else { + factor_ = ss_.AnalyzeCholesky(cholmod_lhs); + } + + if (VLOG_IS_ON(2)) { + cholmod_print_common("Symbolic Analysis", ss_.mutable_cc()); + } } + CHECK_NOTNULL(factor_); + + const time_t symbolic_time = time(NULL); cholmod_dense* cholmod_solution = - ss_.SolveCholesky(cholmod_lhs, symbolic_factor_, cholmod_rhs); + ss_.SolveCholesky(cholmod_lhs, factor_, cholmod_rhs); + + const time_t solve_time = time(NULL); ss_.Free(cholmod_lhs); cholmod_lhs = NULL; ss_.Free(cholmod_rhs); cholmod_rhs = NULL; - // If sparsity is not constant across calls, then reset the symbolic - // factorization. - if (!options().constant_sparsity) { - ss_.Free(symbolic_factor_); - symbolic_factor_ = NULL; - } - if (cholmod_solution == NULL) { LOG(ERROR) << "CHOLMOD solve failed."; return false; @@ -277,9 +326,63 @@ bool SparseSchurComplementSolver::SolveReducedLinearSystem(double* solution) { VectorRef(solution, num_rows) = VectorRef(static_cast(cholmod_solution->x), num_rows); ss_.Free(cholmod_solution); + const time_t final_time = time(NULL); + VLOG(2) << "time: " << (final_time - start_time) + << " lhs : " << (lhs_time - start_time) + << " rhs: " << (rhs_time - lhs_time) + << " analyze: " << (symbolic_time - rhs_time) + << " factor_and_solve: " << (solve_time - symbolic_time) + << " cleanup: " << (final_time - solve_time); return true; } +#else +bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse( + double* solution) { + LOG(FATAL) << "No SuiteSparse support in Ceres."; + return false; +} #endif // CERES_NO_SUITESPARSE +#ifndef CERES_NO_CXSPARSE +// Solve the system Sx = r, assuming that the matrix S is stored in a +// BlockRandomAccessSparseMatrix. The linear system is solved using +// CXSparse's sparse cholesky factorization routines. +bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingCXSparse( + double* solution) { + // Extract the TripletSparseMatrix that is used for actually storing S. + TripletSparseMatrix* tsm = + const_cast( + down_cast(lhs())->matrix()); + + const int num_rows = tsm->num_rows(); + + // The case where there are no f blocks, and the system is block + // diagonal. + if (num_rows == 0) { + return true; + } + + cs_di* lhs = CHECK_NOTNULL(cxsparse_.CreateSparseMatrix(tsm)); + VectorRef(solution, num_rows) = ConstVectorRef(rhs(), num_rows); + + // Compute symbolic factorization if not available. + if (cxsparse_factor_ == NULL) { + cxsparse_factor_ = CHECK_NOTNULL(cxsparse_.AnalyzeCholesky(lhs)); + } + + // Solve the linear system. + bool ok = cxsparse_.SolveCholesky(lhs, cxsparse_factor_, solution); + + cxsparse_.Free(lhs); + return ok; +} +#else +bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingCXSparse( + double* solution) { + LOG(FATAL) << "No CXSparse support in Ceres."; + return false; +} +#endif // CERES_NO_CXPARSE + } // namespace internal } // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h b/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h index 039bc09e3ce..ea1b3184c33 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h +++ b/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h @@ -31,9 +31,13 @@ #ifndef CERES_INTERNAL_SCHUR_COMPLEMENT_SOLVER_H_ #define CERES_INTERNAL_SCHUR_COMPLEMENT_SOLVER_H_ +#include +#include + #include "ceres/block_random_access_matrix.h" #include "ceres/block_sparse_matrix.h" #include "ceres/block_structure.h" +#include "ceres/cxsparse.h" #include "ceres/linear_solver.h" #include "ceres/schur_eliminator.h" #include "ceres/suitesparse.h" @@ -128,7 +132,7 @@ class SchurComplementSolver : public BlockSparseMatrixBaseSolver { scoped_ptr lhs_; scoped_array rhs_; - DISALLOW_COPY_AND_ASSIGN(SchurComplementSolver); + CERES_DISALLOW_COPY_AND_ASSIGN(SchurComplementSolver); }; // Dense Cholesky factorization based solver. @@ -142,10 +146,10 @@ class DenseSchurComplementSolver : public SchurComplementSolver { virtual void InitStorage(const CompressedRowBlockStructure* bs); virtual bool SolveReducedLinearSystem(double* solution); - DISALLOW_COPY_AND_ASSIGN(DenseSchurComplementSolver); + CERES_DISALLOW_COPY_AND_ASSIGN(DenseSchurComplementSolver); }; -#ifndef CERES_NO_SUITESPARSE + // Sparse Cholesky factorization based solver. class SparseSchurComplementSolver : public SchurComplementSolver { public: @@ -155,26 +159,26 @@ class SparseSchurComplementSolver : public SchurComplementSolver { private: virtual void InitStorage(const CompressedRowBlockStructure* bs); virtual bool SolveReducedLinearSystem(double* solution); + bool SolveReducedLinearSystemUsingSuiteSparse(double* solution); + bool SolveReducedLinearSystemUsingCXSparse(double* solution); + // Size of the blocks in the Schur complement. + vector blocks_; +#ifndef CERES_NO_SUITESPARSE SuiteSparse ss_; // Symbolic factorization of the reduced linear system. Precomputed - // once and reused if constant_sparsity_ is true. - cholmod_factor* symbolic_factor_; - DISALLOW_COPY_AND_ASSIGN(SparseSchurComplementSolver); -}; -#else // CERES_NO_SUITESPARSE -class SparseSchurComplementSolver : public SchurComplementSolver { - public: - explicit SparseSchurComplementSolver(const LinearSolver::Options& options) - : SchurComplementSolver(options) { - LOG(FATAL) << "SPARSE_SCHUR is not available. Please " - "build Ceres with SuiteSparse."; - } + // once and reused in subsequent calls. + cholmod_factor* factor_; +#endif // CERES_NO_SUITESPARSE - virtual ~SparseSchurComplementSolver() {} +#ifndef CERES_NO_CXSPARSE + CXSparse cxsparse_; + // Cached factorization + cs_dis* cxsparse_factor_; +#endif // CERES_NO_CXSPARSE + CERES_DISALLOW_COPY_AND_ASSIGN(SparseSchurComplementSolver); }; -#endif // CERES_NO_SUITESPARSE } // namespace internal } // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h b/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h index a388d005424..6120db9b009 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h +++ b/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h @@ -188,7 +188,7 @@ Eliminate(const BlockSparseMatrixBase* A, typename EigenTypes::ConstVectorRef diag(D + bs->cols[i].position, block_size); - MutexLock l(&cell_info->m); + CeresMutexLock l(&cell_info->m); MatrixRef m(cell_info->values, row_stride, col_stride); m.block(r, c, block_size, block_size).diagonal() += diag.array().square().matrix(); @@ -387,7 +387,7 @@ UpdateRhs(const Chunk& chunk, row.block.size, block_size); const int block = block_id - num_eliminate_blocks_; - MutexLock l(rhs_locks_[block]); + CeresMutexLock l(rhs_locks_[block]); typename EigenTypes::VectorRef (rhs + lhs_row_layout_[block], block_size).noalias() += b.transpose() * sj; @@ -523,7 +523,7 @@ ChunkOuterProduct(const CompressedRowBlockStructure* bs, const typename EigenTypes::ConstMatrixRef b2(buffer + it2->second, e_block_size, block2_size); - MutexLock l(&cell_info->m); + CeresMutexLock l(&cell_info->m); MatrixRef m(cell_info->values, row_stride, col_stride); // We explicitly construct a block object here instead of using @@ -532,7 +532,29 @@ ChunkOuterProduct(const CompressedRowBlockStructure* bs, // like the Matrix class does. Eigen::Block block(m, r, c, block1_size, block2_size); - block.noalias() -= b1_transpose_inverse_ete * b2; +#ifdef CERES_WORK_AROUND_ANDROID_NDK_COMPILER_BUG + // Removing the ".noalias()" annotation on the following statement is + // necessary to produce a correct build with the Android NDK, including + // versions 6, 7, 8, and 8b, when built with STLPort and the + // non-standalone toolchain (i.e. ndk-build). This appears to be a + // compiler bug; if the workaround is not in place, the line + // + // block.noalias() -= b1_transpose_inverse_ete * b2; + // + // gets compiled to + // + // block.noalias() += b1_transpose_inverse_ete * b2; + // + // which breaks schur elimination. Introducing a temporary by removing the + // .noalias() annotation causes the issue to disappear. Tracking this + // issue down was tricky, since the test suite doesn't run when built with + // the non-standalone toolchain. + // + // TODO(keir): Make a reproduction case for this and send it upstream. + block -= b1_transpose_inverse_ete * b2; +#else + block.noalias() -= b1_transpose_inverse_ete * b2; +#endif // CERES_WORK_AROUND_ANDROID_NDK_COMPILER_BUG } } } @@ -601,7 +623,7 @@ NoEBlockRowOuterProduct(const BlockSparseMatrixBase* A, &r, &c, &row_stride, &col_stride); if (cell_info != NULL) { - MutexLock l(&cell_info->m); + CeresMutexLock l(&cell_info->m); MatrixRef m(cell_info->values, row_stride, col_stride); m.block(r, c, block1_size, block1_size) .selfadjointView() @@ -621,7 +643,7 @@ NoEBlockRowOuterProduct(const BlockSparseMatrixBase* A, } const int block2_size = bs->cols[row.cells[j].block_id].size; - MutexLock l(&cell_info->m); + CeresMutexLock l(&cell_info->m); MatrixRef m(cell_info->values, row_stride, col_stride); m.block(r, c, block1_size, block2_size).noalias() += b1.transpose() * ConstMatrixRef(row_values + row.cells[j].position, @@ -660,7 +682,7 @@ EBlockRowOuterProduct(const BlockSparseMatrixBase* A, continue; } - MutexLock l(&cell_info->m); + CeresMutexLock l(&cell_info->m); MatrixRef m(cell_info->values, row_stride, col_stride); Eigen::Block @@ -687,7 +709,7 @@ EBlockRowOuterProduct(const BlockSparseMatrixBase* A, row.block.size, block2_size); - MutexLock l(&cell_info->m); + CeresMutexLock l(&cell_info->m); MatrixRef m(cell_info->values, row_stride, col_stride); Eigen::Block block(m, r, c, block1_size, block2_size); diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.cc b/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.cc index c4fc1da3c2f..1cdff4e6dec 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.cc @@ -30,25 +30,14 @@ #include "ceres/schur_ordering.h" -#include #include "ceres/graph.h" #include "ceres/graph_algorithms.h" +#include "ceres/internal/scoped_ptr.h" #include "ceres/map_util.h" #include "ceres/parameter_block.h" #include "ceres/program.h" #include "ceres/residual_block.h" -#include "ceres/internal/scoped_ptr.h" - -CERES_HASH_NAMESPACE_START - -// Allow us to hash pointers as if they were int's -template<> struct hash< ::ceres::internal::ParameterBlock*> { - size_t operator()(::ceres::internal::ParameterBlock* x) const { - return reinterpret_cast(x); - } -}; - -CERES_HASH_NAMESPACE_END +#include "glog/logging.h" namespace ceres { namespace internal { @@ -59,8 +48,7 @@ int ComputeSchurOrdering(const Program& program, scoped_ptr > graph( CHECK_NOTNULL(CreateHessianGraph(program))); - int independent_set_size = - IndependentSetOrdering(*graph, ordering); + int independent_set_size = IndependentSetOrdering(*graph, ordering); const vector& parameter_blocks = program.parameter_blocks(); // Add the excluded blocks to back of the ordering vector. diff --git a/extern/libmv/third_party/ceres/internal/ceres/solver.cc b/extern/libmv/third_party/ceres/internal/ceres/solver.cc index 77f04d1d918..66ca93283a1 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/solver.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/solver.cc @@ -32,36 +32,32 @@ #include "ceres/solver.h" #include -#include "ceres/levenberg_marquardt.h" +#include "ceres/problem.h" +#include "ceres/problem_impl.h" #include "ceres/program.h" #include "ceres/solver_impl.h" #include "ceres/stringprintf.h" -#include "ceres/problem.h" namespace ceres { Solver::~Solver() {} -// TODO(sameeragarwal): The timing code here should use a sub-second -// timer. +// TODO(sameeragarwal): Use subsecond timers. void Solver::Solve(const Solver::Options& options, Problem* problem, Solver::Summary* summary) { time_t start_time_seconds = time(NULL); - internal::SolverImpl::Solve(options, problem, summary); + internal::ProblemImpl* problem_impl = + CHECK_NOTNULL(problem)->problem_impl_.get(); + internal::SolverImpl::Solve(options, problem_impl, summary); summary->total_time_in_seconds = time(NULL) - start_time_seconds; - summary->preprocessor_time_in_seconds = - summary->total_time_in_seconds - summary->minimizer_time_in_seconds; } void Solve(const Solver::Options& options, Problem* problem, Solver::Summary* summary) { - time_t start_time_seconds = time(NULL); - internal::SolverImpl::Solve(options, problem, summary); - summary->total_time_in_seconds = time(NULL) - start_time_seconds; - summary->preprocessor_time_in_seconds = - summary->total_time_in_seconds - summary->minimizer_time_in_seconds; + Solver solver; + solver.Solve(options, problem, summary); } Solver::Summary::Summary() @@ -75,6 +71,7 @@ Solver::Summary::Summary() num_unsuccessful_steps(-1), preprocessor_time_in_seconds(-1.0), minimizer_time_in_seconds(-1.0), + postprocessor_time_in_seconds(-1.0), total_time_in_seconds(-1.0), num_parameter_blocks(-1), num_parameters(-1), @@ -93,7 +90,9 @@ Solver::Summary::Summary() linear_solver_type_given(SPARSE_NORMAL_CHOLESKY), linear_solver_type_used(SPARSE_NORMAL_CHOLESKY), preconditioner_type(IDENTITY), - ordering_type(NATURAL) { + ordering_type(NATURAL), + trust_region_strategy_type(LEVENBERG_MARQUARDT), + sparse_linear_algebra_library(SUITE_SPARSE) { } string Solver::Summary::BriefReport() const { @@ -136,7 +135,7 @@ string Solver::Summary::FullReport() const { num_parameters); internal::StringAppendF(&report, "Residual blocks % 10d\n", num_residual_blocks); - internal::StringAppendF(&report, "Residual % 10d\n\n", + internal::StringAppendF(&report, "Residuals % 10d\n\n", num_residuals); } else { internal::StringAppendF(&report, "%45s %21s\n", "Original", "Reduced"); @@ -183,10 +182,33 @@ string Solver::Summary::FullReport() const { internal::StringAppendF(&report, "Threads: % 25d% 25d\n", num_threads_given, num_threads_used); - internal::StringAppendF(&report, "Linear Solver Threads:% 23d% 25d\n", + internal::StringAppendF(&report, "Linear solver threads % 23d% 25d\n", num_linear_solver_threads_given, num_linear_solver_threads_used); + if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY || + linear_solver_type_used == SPARSE_SCHUR || + (linear_solver_type_used == ITERATIVE_SCHUR && + (preconditioner_type == SCHUR_JACOBI || + preconditioner_type == CLUSTER_JACOBI || + preconditioner_type == CLUSTER_TRIDIAGONAL))) { + internal::StringAppendF(&report, "\nSparse Linear Algebra Library %15s\n", + SparseLinearAlgebraLibraryTypeToString( + sparse_linear_algebra_library)); + } + + internal::StringAppendF(&report, "Trust Region Strategy %19s", + TrustRegionStrategyTypeToString( + trust_region_strategy_type)); + if (trust_region_strategy_type == DOGLEG) { + if (dogleg_type == TRADITIONAL_DOGLEG) { + internal::StringAppendF(&report, " (TRADITIONAL)"); + } else { + internal::StringAppendF(&report, " (SUBSPACE)"); + } + } + internal::StringAppendF(&report, "\n"); + if (termination_type == DID_NOT_RUN) { CHECK(!error.empty()) diff --git a/extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc b/extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc index ed07d9dc6d7..8ef5b98e35f 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc @@ -30,40 +30,29 @@ #include "ceres/solver_impl.h" +#include #include // NOLINT #include #include "ceres/evaluator.h" #include "ceres/gradient_checking_cost_function.h" -#include "ceres/levenberg_marquardt.h" +#include "ceres/iteration_callback.h" +#include "ceres/levenberg_marquardt_strategy.h" #include "ceres/linear_solver.h" #include "ceres/map_util.h" #include "ceres/minimizer.h" #include "ceres/parameter_block.h" +#include "ceres/problem.h" #include "ceres/problem_impl.h" #include "ceres/program.h" #include "ceres/residual_block.h" #include "ceres/schur_ordering.h" #include "ceres/stringprintf.h" -#include "ceres/iteration_callback.h" -#include "ceres/problem.h" +#include "ceres/trust_region_minimizer.h" namespace ceres { namespace internal { namespace { -void EvaluateCostAndResiduals(ProblemImpl* problem_impl, - double* cost, - vector* residuals) { - CHECK_NOTNULL(cost); - Program* program = CHECK_NOTNULL(problem_impl)->mutable_program(); - if (residuals != NULL) { - residuals->resize(program->NumResiduals()); - program->Evaluate(cost, &(*residuals)[0]); - } else { - program->Evaluate(cost, NULL); - } -} - // Callback for updating the user's parameter blocks. Updates are only // done if the step is successful. class StateUpdatingCallback : public IterationCallback { @@ -96,7 +85,7 @@ class LoggingCallback : public IterationCallback { CallbackReturnType operator()(const IterationSummary& summary) { const char* kReportRowFormat = "% 4d: f:% 8e d:% 3.2e g:% 3.2e h:% 3.2e " - "rho:% 3.2e mu:% 3.2e li:% 3d"; + "rho:% 3.2e mu:% 3.2e li:% 3d it:% 3.2e tt:% 3.2e"; string output = StringPrintf(kReportRowFormat, summary.iteration, summary.cost, @@ -104,8 +93,10 @@ class LoggingCallback : public IterationCallback { summary.gradient_max_norm, summary.step_norm, summary.relative_decrease, - summary.mu, - summary.linear_solver_iterations); + summary.trust_region_radius, + summary.linear_solver_iterations, + summary.iteration_time_in_seconds, + summary.cumulative_time_in_seconds); if (log_to_stdout_) { cout << output << endl; } else { @@ -118,44 +109,101 @@ class LoggingCallback : public IterationCallback { const bool log_to_stdout_; }; +// Basic callback to record the execution of the solver to a file for +// offline analysis. +class FileLoggingCallback : public IterationCallback { + public: + explicit FileLoggingCallback(const string& filename) + : fptr_(NULL) { + fptr_ = fopen(filename.c_str(), "w"); + CHECK_NOTNULL(fptr_); + } + + virtual ~FileLoggingCallback() { + if (fptr_ != NULL) { + fclose(fptr_); + } + } + + virtual CallbackReturnType operator()(const IterationSummary& summary) { + fprintf(fptr_, + "%4d %e %e\n", + summary.iteration, + summary.cost, + summary.cumulative_time_in_seconds); + return SOLVER_CONTINUE; + } + private: + FILE* fptr_; +}; + } // namespace void SolverImpl::Minimize(const Solver::Options& options, Program* program, Evaluator* evaluator, LinearSolver* linear_solver, - double* initial_parameters, - double* final_parameters, + double* parameters, Solver::Summary* summary) { Minimizer::Options minimizer_options(options); + // TODO(sameeragarwal): Add support for logging the configuration + // and more detailed stats. + scoped_ptr file_logging_callback; + if (!options.solver_log.empty()) { + file_logging_callback.reset(new FileLoggingCallback(options.solver_log)); + minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(), + file_logging_callback.get()); + } + LoggingCallback logging_callback(options.minimizer_progress_to_stdout); if (options.logging_type != SILENT) { - minimizer_options.callbacks.push_back(&logging_callback); + minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(), + &logging_callback); } - StateUpdatingCallback updating_callback(program, initial_parameters); + StateUpdatingCallback updating_callback(program, parameters); if (options.update_state_every_iteration) { - minimizer_options.callbacks.push_back(&updating_callback); - } - - LevenbergMarquardt levenberg_marquardt; - - time_t start_minimizer_time_seconds = time(NULL); - levenberg_marquardt.Minimize(minimizer_options, - evaluator, - linear_solver, - initial_parameters, - final_parameters, - summary); - summary->minimizer_time_in_seconds = - time(NULL) - start_minimizer_time_seconds; + // This must get pushed to the front of the callbacks so that it is run + // before any of the user callbacks. + minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(), + &updating_callback); + } + + minimizer_options.evaluator = evaluator; + scoped_ptr jacobian(evaluator->CreateJacobian()); + minimizer_options.jacobian = jacobian.get(); + + TrustRegionStrategy::Options trust_region_strategy_options; + trust_region_strategy_options.linear_solver = linear_solver; + trust_region_strategy_options.initial_radius = + options.initial_trust_region_radius; + trust_region_strategy_options.max_radius = options.max_trust_region_radius; + trust_region_strategy_options.lm_min_diagonal = options.lm_min_diagonal; + trust_region_strategy_options.lm_max_diagonal = options.lm_max_diagonal; + trust_region_strategy_options.trust_region_strategy_type = + options.trust_region_strategy_type; + trust_region_strategy_options.dogleg_type = options.dogleg_type; + scoped_ptr strategy( + TrustRegionStrategy::Create(trust_region_strategy_options)); + minimizer_options.trust_region_strategy = strategy.get(); + + TrustRegionMinimizer minimizer; + time_t minimizer_start_time = time(NULL); + minimizer.Minimize(minimizer_options, parameters, summary); + summary->minimizer_time_in_seconds = time(NULL) - minimizer_start_time; } void SolverImpl::Solve(const Solver::Options& original_options, - Problem* problem, + ProblemImpl* original_problem_impl, Solver::Summary* summary) { + time_t solver_start_time = time(NULL); Solver::Options options(original_options); + Program* original_program = original_problem_impl->mutable_program(); + ProblemImpl* problem_impl = original_problem_impl; + // Reset the summary object to its default values. + *CHECK_NOTNULL(summary) = Solver::Summary(); + #ifndef CERES_USE_OPENMP if (options.num_threads > 1) { @@ -174,8 +222,6 @@ void SolverImpl::Solve(const Solver::Options& original_options, } #endif - // Reset the summary object to its default values; - *CHECK_NOTNULL(summary) = Solver::Summary(); summary->linear_solver_type_given = options.linear_solver_type; summary->num_eliminate_blocks_given = original_options.num_eliminate_blocks; summary->num_threads_given = original_options.num_threads; @@ -183,32 +229,38 @@ void SolverImpl::Solve(const Solver::Options& original_options, original_options.num_linear_solver_threads; summary->ordering_type = original_options.ordering_type; - ProblemImpl* problem_impl = CHECK_NOTNULL(problem)->problem_impl_.get(); - summary->num_parameter_blocks = problem_impl->NumParameterBlocks(); summary->num_parameters = problem_impl->NumParameters(); summary->num_residual_blocks = problem_impl->NumResidualBlocks(); summary->num_residuals = problem_impl->NumResiduals(); summary->num_threads_used = options.num_threads; - - // Evaluate the initial cost and residual vector (if needed). The - // initial cost needs to be computed on the original unpreprocessed - // problem, as it is used to determine the value of the "fixed" part - // of the objective function after the problem has undergone - // reduction. Also the initial residuals are in the order in which - // the user added the ResidualBlocks to the optimization problem. - EvaluateCostAndResiduals(problem_impl, - &summary->initial_cost, - options.return_initial_residuals - ? &summary->initial_residuals - : NULL); + summary->sparse_linear_algebra_library = + options.sparse_linear_algebra_library; + summary->trust_region_strategy_type = options.trust_region_strategy_type; + summary->dogleg_type = options.dogleg_type; + + // Evaluate the initial cost, residual vector and the jacobian + // matrix if requested by the user. The initial cost needs to be + // computed on the original unpreprocessed problem, as it is used to + // determine the value of the "fixed" part of the objective function + // after the problem has undergone reduction. + Evaluator::Evaluate( + original_program, + options.num_threads, + &(summary->initial_cost), + options.return_initial_residuals ? &summary->initial_residuals : NULL, + options.return_initial_gradient ? &summary->initial_gradient : NULL, + options.return_initial_jacobian ? &summary->initial_jacobian : NULL); + original_program->SetParameterBlockStatePtrsToUserStatePtrs(); // If the user requests gradient checking, construct a new // ProblemImpl by wrapping the CostFunctions of problem_impl inside // GradientCheckingCostFunction and replacing problem_impl with // gradient_checking_problem_impl. scoped_ptr gradient_checking_problem_impl; + // Save the original problem impl so we don't use the gradient + // checking one when computing the residuals. if (options.check_gradients) { VLOG(1) << "Checking Gradients"; gradient_checking_problem_impl.reset( @@ -224,8 +276,10 @@ void SolverImpl::Solve(const Solver::Options& original_options, // Create the three objects needed to minimize: the transformed program, the // evaluator, and the linear solver. - scoped_ptr reduced_program( - CreateReducedProgram(&options, problem_impl, &summary->error)); + scoped_ptr reduced_program(CreateReducedProgram(&options, + problem_impl, + &summary->fixed_cost, + &summary->error)); if (reduced_program == NULL) { return; } @@ -259,19 +313,21 @@ void SolverImpl::Solve(const Solver::Options& original_options, } // The optimizer works on contiguous parameter vectors; allocate some. - Vector initial_parameters(reduced_program->NumParameters()); - Vector optimized_parameters(reduced_program->NumParameters()); + Vector parameters(reduced_program->NumParameters()); // Collect the discontiguous parameters into a contiguous state vector. - reduced_program->ParameterBlocksToStateVector(&initial_parameters[0]); + reduced_program->ParameterBlocksToStateVector(parameters.data()); + + time_t minimizer_start_time = time(NULL); + summary->preprocessor_time_in_seconds = + minimizer_start_time - solver_start_time; // Run the optimization. Minimize(options, reduced_program.get(), evaluator.get(), linear_solver.get(), - initial_parameters.data(), - optimized_parameters.data(), + parameters.data(), summary); // If the user aborted mid-optimization or the optimization @@ -282,30 +338,45 @@ void SolverImpl::Solve(const Solver::Options& original_options, return; } + time_t post_process_start_time = time(NULL); + // Push the contiguous optimized parameters back to the user's parameters. - reduced_program->StateVectorToParameterBlocks(&optimized_parameters[0]); + reduced_program->StateVectorToParameterBlocks(parameters.data()); reduced_program->CopyParameterBlockStateToUserState(); - // Return the final cost and residuals for the original problem. - EvaluateCostAndResiduals(problem->problem_impl_.get(), - &summary->final_cost, - options.return_final_residuals - ? &summary->final_residuals - : NULL); - + // Evaluate the final cost, residual vector and the jacobian + // matrix if requested by the user. + Evaluator::Evaluate( + original_program, + options.num_threads, + &summary->final_cost, + options.return_final_residuals ? &summary->final_residuals : NULL, + options.return_final_gradient ? &summary->final_gradient : NULL, + options.return_final_jacobian ? &summary->final_jacobian : NULL); + + // Ensure the program state is set to the user parameters on the way out. + original_program->SetParameterBlockStatePtrsToUserStatePtrs(); // Stick a fork in it, we're done. - return; + summary->postprocessor_time_in_seconds = time(NULL) - post_process_start_time; } // Strips varying parameters and residuals, maintaining order, and updating // num_eliminate_blocks. bool SolverImpl::RemoveFixedBlocksFromProgram(Program* program, int* num_eliminate_blocks, + double* fixed_cost, string* error) { int original_num_eliminate_blocks = *num_eliminate_blocks; vector* parameter_blocks = program->mutable_parameter_blocks(); + scoped_array residual_block_evaluate_scratch; + if (fixed_cost != NULL) { + residual_block_evaluate_scratch.reset( + new double[program->MaxScratchDoublesNeededForEvaluate()]); + *fixed_cost = 0.0; + } + // Mark all the parameters as unused. Abuse the index member of the parameter // blocks for the marking. for (int i = 0; i < parameter_blocks->size(); ++i) { @@ -335,6 +406,17 @@ bool SolverImpl::RemoveFixedBlocksFromProgram(Program* program, if (!all_constant) { (*residual_blocks)[j++] = (*residual_blocks)[i]; + } else if (fixed_cost != NULL) { + // The residual is constant and will be removed, so its cost is + // added to the variable fixed_cost. + double cost = 0.0; + if (!residual_block->Evaluate( + &cost, NULL, NULL, residual_block_evaluate_scratch.get())) { + *error = StringPrintf("Evaluation of the residual %d failed during " + "removal of fixed residual blocks.", i); + return false; + } + *fixed_cost += cost; } } residual_blocks->resize(j); @@ -367,6 +449,7 @@ bool SolverImpl::RemoveFixedBlocksFromProgram(Program* program, Program* SolverImpl::CreateReducedProgram(Solver::Options* options, ProblemImpl* problem_impl, + double* fixed_cost, string* error) { Program* original_program = problem_impl->mutable_program(); scoped_ptr transformed_program(new Program(*original_program)); @@ -397,6 +480,7 @@ Program* SolverImpl::CreateReducedProgram(Solver::Options* options, if (!RemoveFixedBlocksFromProgram(transformed_program.get(), &num_eliminate_blocks, + fixed_cost, error)) { return NULL; } @@ -431,13 +515,34 @@ Program* SolverImpl::CreateReducedProgram(Solver::Options* options, LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options, string* error) { + if (options->trust_region_strategy_type == DOGLEG) { + if (options->linear_solver_type == ITERATIVE_SCHUR || + options->linear_solver_type == CGNR) { + *error = "DOGLEG only supports exact factorization based linear " + "solvers. If you want to use an iterative solver please " + "use LEVENBERG_MARQUARDT as the trust_region_strategy_type"; + return NULL; + } + } + #ifdef CERES_NO_SUITESPARSE - if (options->linear_solver_type == SPARSE_NORMAL_CHOLESKY) { - *error = "Can't use SPARSE_NORMAL_CHOLESKY because SuiteSparse was not " - "enabled when Ceres was built."; + if (options->linear_solver_type == SPARSE_NORMAL_CHOLESKY && + options->sparse_linear_algebra_library == SUITE_SPARSE) { + *error = "Can't use SPARSE_NORMAL_CHOLESKY with SUITESPARSE because " + "SuiteSparse was not enabled when Ceres was built."; + return NULL; + } +#endif + +#ifdef CERES_NO_CXSPARSE + if (options->linear_solver_type == SPARSE_NORMAL_CHOLESKY && + options->sparse_linear_algebra_library == CX_SPARSE) { + *error = "Can't use SPARSE_NORMAL_CHOLESKY with CXSPARSE because " + "CXSparse was not enabled when Ceres was built."; return NULL; } -#endif // CERES_NO_SUITESPARSE +#endif + if (options->linear_solver_max_num_iterations <= 0) { *error = "Solver::Options::linear_solver_max_num_iterations is 0."; @@ -455,30 +560,32 @@ LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options, } LinearSolver::Options linear_solver_options; - linear_solver_options.constant_sparsity = true; linear_solver_options.min_num_iterations = options->linear_solver_min_num_iterations; linear_solver_options.max_num_iterations = options->linear_solver_max_num_iterations; linear_solver_options.type = options->linear_solver_type; linear_solver_options.preconditioner_type = options->preconditioner_type; + linear_solver_options.sparse_linear_algebra_library = + options->sparse_linear_algebra_library; + linear_solver_options.use_block_amd = options->use_block_amd; #ifdef CERES_NO_SUITESPARSE if (linear_solver_options.preconditioner_type == SCHUR_JACOBI) { *error = "SCHUR_JACOBI preconditioner not suppored. Please build Ceres " - "with SuiteSparse support"; + "with SuiteSparse support."; return NULL; } if (linear_solver_options.preconditioner_type == CLUSTER_JACOBI) { *error = "CLUSTER_JACOBI preconditioner not suppored. Please build Ceres " - "with SuiteSparse support"; + "with SuiteSparse support."; return NULL; } if (linear_solver_options.preconditioner_type == CLUSTER_TRIDIAGONAL) { *error = "CLUSTER_TRIDIAGONAL preconditioner not suppored. Please build " - "Ceres with SuiteSparse support"; + "Ceres with SuiteSparse support."; return NULL; } #endif @@ -489,23 +596,23 @@ LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options, if ((linear_solver_options.num_eliminate_blocks == 0) && IsSchurType(linear_solver_options.type)) { -#ifndef CERES_NO_SUITESPARSE +#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE) + LOG(INFO) << "No elimination block remaining switching to DENSE_QR."; + linear_solver_options.type = DENSE_QR; +#else LOG(INFO) << "No elimination block remaining " << "switching to SPARSE_NORMAL_CHOLESKY."; linear_solver_options.type = SPARSE_NORMAL_CHOLESKY; -#else - LOG(INFO) << "No elimination block remaining switching to DENSE_QR."; - linear_solver_options.type = DENSE_QR; -#endif // CERES_NO_SUITESPARSE +#endif } -#ifdef CERES_NO_SUITESPARSE +#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE) if (linear_solver_options.type == SPARSE_SCHUR) { - *error = "Can't use SPARSE_SCHUR because SuiteSparse was not " - "enabled when Ceres was built."; + *error = "Can't use SPARSE_SCHUR because neither SuiteSparse nor" + "CXSparse was enabled when Ceres was compiled."; return NULL; } -#endif // CERES_NO_SUITESPARSE +#endif // The matrix used for storing the dense Schur complement has a // single lock guarding the whole matrix. Running the @@ -578,15 +685,18 @@ bool SolverImpl::ApplyUserOrdering(const ProblemImpl& problem_impl, // Find the minimum index of any parameter block to the given residual. // Parameter blocks that have indices greater than num_eliminate_blocks are // considered to have an index equal to num_eliminate_blocks. -int MinParameterBlock(const ResidualBlock* residual_block, - int num_eliminate_blocks) { +static int MinParameterBlock(const ResidualBlock* residual_block, + int num_eliminate_blocks) { int min_parameter_block_position = num_eliminate_blocks; for (int i = 0; i < residual_block->NumParameterBlocks(); ++i) { ParameterBlock* parameter_block = residual_block->parameter_blocks()[i]; - DCHECK_NE(parameter_block->index(), -1) - << "Did you forget to call Program::SetParameterOffsetsAndIndex()?"; - min_parameter_block_position = std::min(parameter_block->index(), - min_parameter_block_position); + if (!parameter_block->IsConstant()) { + CHECK_NE(parameter_block->index(), -1) + << "Did you forget to call Program::SetParameterOffsetsAndIndex()? " + << "This is a Ceres bug; please contact the developers!"; + min_parameter_block_position = std::min(parameter_block->index(), + min_parameter_block_position); + } } return min_parameter_block_position; } diff --git a/extern/libmv/third_party/ceres/internal/ceres/solver_impl.h b/extern/libmv/third_party/ceres/internal/ceres/solver_impl.h index 957ebcc65df..11b44de6f42 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/solver_impl.h +++ b/extern/libmv/third_party/ceres/internal/ceres/solver_impl.h @@ -31,6 +31,9 @@ #ifndef CERES_INTERNAL_SOLVER_IMPL_H_ #define CERES_INTERNAL_SOLVER_IMPL_H_ +#include +#include +#include "ceres/internal/port.h" #include "ceres/solver.h" namespace ceres { @@ -46,15 +49,18 @@ class SolverImpl { // Mirrors the interface in solver.h, but exposes implementation // details for testing internally. static void Solve(const Solver::Options& options, - Problem* problem, + ProblemImpl* problem_impl, Solver::Summary* summary); // Create the transformed Program, which has all the fixed blocks // and residuals eliminated, and in the case of automatic schur // ordering, has the E blocks first in the resulting program, with // options.num_eliminate_blocks set appropriately. + // If fixed_cost is not NULL, the residual blocks that are removed + // are evaluated and the sum of their cost is returned in fixed_cost. static Program* CreateReducedProgram(Solver::Options* options, ProblemImpl* problem_impl, + double* fixed_cost, string* error); // Create the appropriate linear solver, taking into account any @@ -92,16 +98,18 @@ class SolverImpl { Program* program, Evaluator* evaluator, LinearSolver* linear_solver, - double* initial_parameters, - double* final_parameters, + double* parameters, Solver::Summary* summary); // Remove the fixed or unused parameter blocks and residuals // depending only on fixed parameters from the problem. Also updates // num_eliminate_blocks, since removed parameters changes the point // at which the eliminated blocks is valid. + // If fixed_cost is not NULL, the residual blocks that are removed + // are evaluated and the sum of their cost is returned in fixed_cost. static bool RemoveFixedBlocksFromProgram(Program* program, int* num_eliminate_blocks, + double* fixed_cost, string* error); }; diff --git a/extern/libmv/third_party/ceres/internal/ceres/sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/sparse_matrix.h index 562210dfec8..1b19f887946 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/sparse_matrix.h +++ b/extern/libmv/third_party/ceres/internal/ceres/sparse_matrix.h @@ -86,7 +86,7 @@ class SparseMatrix : public LinearOperator { // sparse matrix. virtual void ToDenseMatrix(Matrix* dense_matrix) const = 0; -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS // Dump the sparse matrix to a proto. Destroys the contents of proto. virtual void ToProto(SparseMatrixProto* proto) const = 0; #endif diff --git a/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc index 59222dc374d..9e00b4402dc 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc @@ -28,13 +28,16 @@ // // Author: sameeragarwal@google.com (Sameer Agarwal) -#ifndef CERES_NO_SUITESPARSE - #include "ceres/sparse_normal_cholesky_solver.h" #include #include #include + +#ifndef CERES_NO_CXSPARSE +#include "cs.h" +#endif + #include "ceres/compressed_row_sparse_matrix.h" #include "ceres/linear_solver.h" #include "ceres/suitesparse.h" @@ -48,13 +51,30 @@ namespace internal { SparseNormalCholeskySolver::SparseNormalCholeskySolver( const LinearSolver::Options& options) - : options_(options), symbolic_factor_(NULL) {} + : options_(options) { +#ifndef CERES_NO_SUITESPARSE + factor_ = NULL; +#endif + +#ifndef CERES_NO_CXSPARSE + cxsparse_factor_ = NULL; +#endif // CERES_NO_CXSPARSE +} SparseNormalCholeskySolver::~SparseNormalCholeskySolver() { - if (symbolic_factor_ != NULL) { - ss_.Free(symbolic_factor_); - symbolic_factor_ = NULL; +#ifndef CERES_NO_SUITESPARSE + if (factor_ != NULL) { + ss_.Free(factor_); + factor_ = NULL; } +#endif + +#ifndef CERES_NO_CXSPARSE + if (cxsparse_factor_ != NULL) { + cxsparse_.Free(cxsparse_factor_); + cxsparse_factor_ = NULL; + } +#endif // CERES_NO_CXSPARSE } LinearSolver::Summary SparseNormalCholeskySolver::SolveImpl( @@ -62,6 +82,93 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImpl( const double* b, const LinearSolver::PerSolveOptions& per_solve_options, double * x) { + switch (options_.sparse_linear_algebra_library) { + case SUITE_SPARSE: + return SolveImplUsingSuiteSparse(A, b, per_solve_options, x); + case CX_SPARSE: + return SolveImplUsingCXSparse(A, b, per_solve_options, x); + default: + LOG(FATAL) << "Unknown sparse linear algebra library : " + << options_.sparse_linear_algebra_library; + } + + LOG(FATAL) << "Unknown sparse linear algebra library : " + << options_.sparse_linear_algebra_library; + return LinearSolver::Summary(); +} + +#ifndef CERES_NO_CXSPARSE +LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingCXSparse( + CompressedRowSparseMatrix* A, + const double* b, + const LinearSolver::PerSolveOptions& per_solve_options, + double * x) { + LinearSolver::Summary summary; + summary.num_iterations = 1; + const int num_cols = A->num_cols(); + Vector Atb = Vector::Zero(num_cols); + A->LeftMultiply(b, Atb.data()); + + if (per_solve_options.D != NULL) { + // Temporarily append a diagonal block to the A matrix, but undo + // it before returning the matrix to the user. + CompressedRowSparseMatrix D(per_solve_options.D, num_cols); + A->AppendRows(D); + } + + VectorRef(x, num_cols).setZero(); + + // Wrap the augmented Jacobian in a compressed sparse column matrix. + cs_di At = cxsparse_.CreateSparseMatrixTransposeView(A); + + // Compute the normal equations. J'J delta = J'f and solve them + // using a sparse Cholesky factorization. Notice that when compared + // to SuiteSparse we have to explicitly compute the transpose of Jt, + // and then the normal equations before they can be + // factorized. CHOLMOD/SuiteSparse on the other hand can just work + // off of Jt to compute the Cholesky factorization of the normal + // equations. + cs_di* A2 = cs_transpose(&At, 1); + cs_di* AtA = cs_multiply(&At,A2); + + cxsparse_.Free(A2); + if (per_solve_options.D != NULL) { + A->DeleteRows(num_cols); + } + + // Compute symbolic factorization if not available. + if (cxsparse_factor_ == NULL) { + cxsparse_factor_ = CHECK_NOTNULL(cxsparse_.AnalyzeCholesky(AtA)); + } + + // Solve the linear system. + if (cxsparse_.SolveCholesky(AtA, cxsparse_factor_, Atb.data())) { + VectorRef(x, Atb.rows()) = Atb; + summary.termination_type = TOLERANCE; + } + + cxsparse_.Free(AtA); + return summary; +} +#else +LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingCXSparse( + CompressedRowSparseMatrix* A, + const double* b, + const LinearSolver::PerSolveOptions& per_solve_options, + double * x) { + LOG(FATAL) << "No CXSparse support in Ceres."; + + // Unreachable but MSVC does not know this. + return LinearSolver::Summary(); +} +#endif + +#ifndef CERES_NO_SUITESPARSE +LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse( + CompressedRowSparseMatrix* A, + const double* b, + const LinearSolver::PerSolveOptions& per_solve_options, + double * x) { const time_t start_time = time(NULL); const int num_cols = A->num_cols(); @@ -84,13 +191,25 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImpl( cholmod_dense* rhs = ss_.CreateDenseVector(Atb.data(), num_cols, num_cols); const time_t init_time = time(NULL); - if (symbolic_factor_ == NULL) { - symbolic_factor_ = CHECK_NOTNULL(ss_.AnalyzeCholesky(lhs.get())); + if (factor_ == NULL) { + if (options_.use_block_amd) { + factor_ = ss_.BlockAnalyzeCholesky(lhs.get(), + A->col_blocks(), + A->row_blocks()); + } else { + factor_ = ss_.AnalyzeCholesky(lhs.get()); + } + + if (VLOG_IS_ON(2)) { + cholmod_print_common("Symbolic Analysis", ss_.mutable_cc()); + } } + CHECK_NOTNULL(factor_); + const time_t symbolic_time = time(NULL); - cholmod_dense* sol = ss_.SolveCholesky(lhs.get(), symbolic_factor_, rhs); + cholmod_dense* sol = ss_.SolveCholesky(lhs.get(), factor_, rhs); const time_t solve_time = time(NULL); ss_.Free(rhs); @@ -100,11 +219,6 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImpl( A->DeleteRows(num_cols); } - if (!options_.constant_sparsity) { - ss_.Free(symbolic_factor_); - symbolic_factor_ = NULL; - } - summary.num_iterations = 1; if (sol != NULL) { memcpy(x, sol->x, num_cols * sizeof(*x)); @@ -115,15 +229,25 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImpl( } const time_t cleanup_time = time(NULL); - VLOG(2) << "time (sec) total: " << cleanup_time - start_time - << " init: " << init_time - start_time - << " symbolic: " << symbolic_time - init_time - << " solve: " << solve_time - symbolic_time - << " cleanup: " << cleanup_time - solve_time; + VLOG(2) << "time (sec) total: " << (cleanup_time - start_time) + << " init: " << (init_time - start_time) + << " symbolic: " << (symbolic_time - init_time) + << " solve: " << (solve_time - symbolic_time) + << " cleanup: " << (cleanup_time - solve_time); return summary; } +#else +LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse( + CompressedRowSparseMatrix* A, + const double* b, + const LinearSolver::PerSolveOptions& per_solve_options, + double * x) { + LOG(FATAL) << "No SuiteSparse support in Ceres."; + + // Unreachable but MSVC does not know this. + return LinearSolver::Summary(); +} +#endif } // namespace internal } // namespace ceres - -#endif // CERES_NO_SUITESPARSE diff --git a/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h b/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h index ce1d6d285be..40d9e0a0327 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h +++ b/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h @@ -34,13 +34,10 @@ #ifndef CERES_INTERNAL_SPARSE_NORMAL_CHOLESKY_SOLVER_H_ #define CERES_INTERNAL_SPARSE_NORMAL_CHOLESKY_SOLVER_H_ -#ifndef CERES_NO_SUITESPARSE - -#include "cholmod.h" -#include "cholmod_core.h" +#include "ceres/cxsparse.h" #include "ceres/linear_solver.h" -#include "ceres/suitesparse.h" #include "ceres/internal/macros.h" +#include "ceres/suitesparse.h" namespace ceres { namespace internal { @@ -61,17 +58,36 @@ class SparseNormalCholeskySolver : public CompressedRowSparseMatrixSolver { const LinearSolver::PerSolveOptions& options, double* x); - const LinearSolver::Options options_; + LinearSolver::Summary SolveImplUsingSuiteSparse( + CompressedRowSparseMatrix* A, + const double* b, + const LinearSolver::PerSolveOptions& options, + double* x); + + // Crashes if CSparse is not installed. + LinearSolver::Summary SolveImplUsingCXSparse( + CompressedRowSparseMatrix* A, + const double* b, + const LinearSolver::PerSolveOptions& options, + double* x); + +#ifndef CERES_NO_SUITESPARSE SuiteSparse ss_; + // Cached factorization + cholmod_factor* factor_; +#endif // CERES_NO_SUITESPARSE +#ifndef CERES_NO_CXSPARSE + CXSparse cxsparse_; // Cached factorization - cholmod_factor* symbolic_factor_; - DISALLOW_COPY_AND_ASSIGN(SparseNormalCholeskySolver); + cs_dis* cxsparse_factor_; +#endif // CERES_NO_CXSPARSE + + const LinearSolver::Options options_; + CERES_DISALLOW_COPY_AND_ASSIGN(SparseNormalCholeskySolver); }; } // namespace internal } // namespace ceres -#endif // CERES_NO_SUITESPARSE - #endif // CERES_INTERNAL_SPARSE_NORMAL_CHOLESKY_SOLVER_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/split.cc b/extern/libmv/third_party/ceres/internal/ceres/split.cc index 4fa1bd468b9..c65c8a5bb5d 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/split.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/split.cc @@ -31,6 +31,7 @@ #include #include #include +#include "ceres/split.h" #include "ceres/internal/port.h" namespace ceres { diff --git a/extern/libmv/third_party/ceres/internal/ceres/split.h b/extern/libmv/third_party/ceres/internal/ceres/split.h new file mode 100644 index 00000000000..ec579e974da --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/split.h @@ -0,0 +1,21 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// Author: keir@google.com (Keir Mierle) + +#ifndef CERES_INTERNAL_SPLIT_H_ +#define VISION_OPTIMIZATION_LEAST_SQUARES_INTERNAL_SPLIT_H_ + +#include +#include +#include "ceres/internal/port.h" + +namespace ceres { + +// Split a string using one or more character delimiters, presented as a +// nul-terminated c string. Append the components to 'result'. If there are +// consecutive delimiters, this function skips over all of them. +void SplitStringUsing(const string& full, const char* delim, + vector* res); + +} // namespace ceres + +#endif // CERES_INTERNAL_SPLIT_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc index c0f35225bc3..396a48b7d97 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc @@ -34,6 +34,7 @@ #include #include +#include "ceres/stringprintf.h" #include "ceres/internal/port.h" namespace ceres { diff --git a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h index 30b974e7ae5..f2f907ab32d 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h +++ b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h @@ -54,34 +54,34 @@ namespace internal { // N.B.: As the GCC manual states, "[s]ince non-static C++ methods // have an implicit 'this' argument, the arguments of such methods // should be counted from two, not one." -#define PRINTF_ATTRIBUTE(string_index, first_to_check) \ +#define CERES_PRINTF_ATTRIBUTE(string_index, first_to_check) \ __attribute__((__format__ (__printf__, string_index, first_to_check))) -#define SCANF_ATTRIBUTE(string_index, first_to_check) \ +#define CERES_SCANF_ATTRIBUTE(string_index, first_to_check) \ __attribute__((__format__ (__scanf__, string_index, first_to_check))) #else -#define PRINTF_ATTRIBUTE(string_index, first_to_check) +#define CERES_PRINTF_ATTRIBUTE(string_index, first_to_check) #endif // Return a C++ string. extern string StringPrintf(const char* format, ...) // Tell the compiler to do printf format string checking. - PRINTF_ATTRIBUTE(1,2); + CERES_PRINTF_ATTRIBUTE(1,2); // Store result into a supplied string and return it. extern const string& SStringPrintf(string* dst, const char* format, ...) // Tell the compiler to do printf format string checking. - PRINTF_ATTRIBUTE(2,3); + CERES_PRINTF_ATTRIBUTE(2,3); // Append result to a supplied string. extern void StringAppendF(string* dst, const char* format, ...) // Tell the compiler to do printf format string checking. - PRINTF_ATTRIBUTE(2,3); + CERES_PRINTF_ATTRIBUTE(2,3); // Lower-level routine that takes a va_list and appends to a specified string. // All other routines are just convenience wrappers around it. extern void StringAppendV(string* dst, const char* format, va_list ap); -#undef PRINTF_ATTRIBUTE +#undef CERES_PRINTF_ATTRIBUTE } // namespace internal } // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc index 1cf6a7496a7..cf3c48f84e6 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc @@ -29,15 +29,14 @@ // Author: sameeragarwal@google.com (Sameer Agarwal) #ifndef CERES_NO_SUITESPARSE - #include "ceres/suitesparse.h" +#include #include "cholmod.h" #include "ceres/compressed_row_sparse_matrix.h" #include "ceres/triplet_sparse_matrix.h" namespace ceres { namespace internal { - cholmod_sparse* SuiteSparse::CreateSparseMatrix(TripletSparseMatrix* A) { cholmod_triplet triplet; @@ -111,6 +110,13 @@ cholmod_dense* SuiteSparse::CreateDenseVector(const double* x, } cholmod_factor* SuiteSparse::AnalyzeCholesky(cholmod_sparse* A) { + // Cholmod can try multiple re-ordering strategies to find a fill + // reducing ordering. Here we just tell it use AMD with automatic + // matrix dependence choice of supernodal versus simplicial + // factorization. + cc_.nmethods = 1; + cc_.method[0].ordering = CHOLMOD_AMD; + cc_.supernodal = CHOLMOD_AUTO; cholmod_factor* factor = cholmod_analyze(A, &cc_); CHECK_EQ(cc_.status, CHOLMOD_OK) << "Cholmod symbolic analysis failed " << cc_.status; @@ -118,6 +124,153 @@ cholmod_factor* SuiteSparse::AnalyzeCholesky(cholmod_sparse* A) { return factor; } +cholmod_factor* SuiteSparse::BlockAnalyzeCholesky( + cholmod_sparse* A, + const vector& row_blocks, + const vector& col_blocks) { + vector ordering; + if (!BlockAMDOrdering(A, row_blocks, col_blocks, &ordering)) { + return NULL; + } + return AnalyzeCholeskyWithUserOrdering(A, ordering); +} + +cholmod_factor* SuiteSparse::AnalyzeCholeskyWithUserOrdering(cholmod_sparse* A, + const vector& ordering) { + CHECK_EQ(ordering.size(), A->nrow); + cc_.nmethods = 1 ; + cc_.method[0].ordering = CHOLMOD_GIVEN; + cholmod_factor* factor = + cholmod_analyze_p(A, const_cast(&ordering[0]), NULL, 0, &cc_); + CHECK_EQ(cc_.status, CHOLMOD_OK) + << "Cholmod symbolic analysis failed " << cc_.status; + CHECK_NOTNULL(factor); + return factor; +} + +bool SuiteSparse::BlockAMDOrdering(const cholmod_sparse* A, + const vector& row_blocks, + const vector& col_blocks, + vector* ordering) { + const int num_row_blocks = row_blocks.size(); + const int num_col_blocks = col_blocks.size(); + + // Arrays storing the compressed column structure of the matrix + // incoding the block sparsity of A. + vector block_cols; + vector block_rows; + + ScalarMatrixToBlockMatrix(A, + row_blocks, + col_blocks, + &block_rows, + &block_cols); + + cholmod_sparse_struct block_matrix; + block_matrix.nrow = num_row_blocks; + block_matrix.ncol = num_col_blocks; + block_matrix.nzmax = block_rows.size(); + block_matrix.p = reinterpret_cast(&block_cols[0]); + block_matrix.i = reinterpret_cast(&block_rows[0]); + block_matrix.x = NULL; + block_matrix.stype = A->stype; + block_matrix.itype = CHOLMOD_INT; + block_matrix.xtype = CHOLMOD_PATTERN; + block_matrix.dtype = CHOLMOD_DOUBLE; + block_matrix.sorted = 1; + block_matrix.packed = 1; + + vector block_ordering(num_row_blocks); + if (!cholmod_amd(&block_matrix, NULL, 0, &block_ordering[0], &cc_)) { + return false; + } + + BlockOrderingToScalarOrdering(row_blocks, block_ordering, ordering); + return true; +} + +void SuiteSparse::ScalarMatrixToBlockMatrix(const cholmod_sparse* A, + const vector& row_blocks, + const vector& col_blocks, + vector* block_rows, + vector* block_cols) { + CHECK_NOTNULL(block_rows)->clear(); + CHECK_NOTNULL(block_cols)->clear(); + const int num_row_blocks = row_blocks.size(); + const int num_col_blocks = col_blocks.size(); + + vector row_block_starts(num_row_blocks); + for (int i = 0, cursor = 0; i < num_row_blocks; ++i) { + row_block_starts[i] = cursor; + cursor += row_blocks[i]; + } + + // The reinterpret_cast is needed here because CHOLMOD stores arrays + // as void*. + const int* scalar_cols = reinterpret_cast(A->p); + const int* scalar_rows = reinterpret_cast(A->i); + + // This loop extracts the block sparsity of the scalar sparse matrix + // A. It does so by iterating over the columns, but only considering + // the columns corresponding to the first element of each column + // block. Within each column, the inner loop iterates over the rows, + // and detects the presence of a row block by checking for the + // presence of a non-zero entry corresponding to its first element. + block_cols->push_back(0); + int c = 0; + for (int col_block = 0; col_block < num_col_blocks; ++col_block) { + int column_size = 0; + for (int idx = scalar_cols[c]; idx < scalar_cols[c + 1]; ++idx) { + vector::const_iterator it = lower_bound(row_block_starts.begin(), + row_block_starts.end(), + scalar_rows[idx]); + // Since we are using lower_bound, it will return the row id + // where the row block starts. For everything but the first row + // of the block, where these values will be the same, we can + // skip, as we only need the first row to detect the presence of + // the block. + // + // For rows all but the first row in the last row block, + // lower_bound will return row_block_starts.end(), but those can + // be skipped like the rows in other row blocks too. + if (it == row_block_starts.end() || *it != scalar_rows[idx]) { + continue; + } + + block_rows->push_back(it - row_block_starts.begin()); + ++column_size; + } + block_cols->push_back(block_cols->back() + column_size); + c += col_blocks[col_block]; + } +} + +void SuiteSparse::BlockOrderingToScalarOrdering( + const vector& blocks, + const vector& block_ordering, + vector* scalar_ordering) { + CHECK_EQ(blocks.size(), block_ordering.size()); + const int num_blocks = blocks.size(); + + // block_starts = [0, block1, block1 + block2 ..] + vector block_starts(num_blocks); + for (int i = 0, cursor = 0; i < num_blocks ; ++i) { + block_starts[i] = cursor; + cursor += blocks[i]; + } + + scalar_ordering->resize(block_starts.back() + blocks.back()); + int cursor = 0; + for (int i = 0; i < num_blocks; ++i) { + const int block_id = block_ordering[i]; + const int block_size = blocks[block_id]; + int block_position = block_starts[block_id]; + for (int j = 0; j < block_size; ++j) { + (*scalar_ordering)[cursor++] = block_position++; + } + } +} + bool SuiteSparse::Cholesky(cholmod_sparse* A, cholmod_factor* L) { CHECK_NOTNULL(A); CHECK_NOTNULL(L); diff --git a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h index 091e67a69a9..eb691c0c0ed 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h +++ b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h @@ -37,6 +37,7 @@ #include #include +#include #include #include "cholmod.h" @@ -105,12 +106,35 @@ class SuiteSparse { cholmod_sdmult(A, 0, alpha_, beta_, x, y, &cc_); } - // Analyze the sparsity structure of the matrix A compute the - // symbolic factorization of A. A is not modified, only the pattern - // of non-zeros of A is used, the actual numerical values in A are - // of no consequence. Caller owns the result. + // Find an ordering of A or AA' (if A is unsymmetric) that minimizes + // the fill-in in the Cholesky factorization of the corresponding + // matrix. This is done by using the AMD algorithm. + // + // Using this ordering, the symbolic Cholesky factorization of A (or + // AA') is computed and returned. + // + // A is not modified, only the pattern of non-zeros of A is used, + // the actual numerical values in A are of no consequence. + // + // Caller owns the result. cholmod_factor* AnalyzeCholesky(cholmod_sparse* A); + cholmod_factor* BlockAnalyzeCholesky(cholmod_sparse* A, + const vector& row_blocks, + const vector& col_blocks); + + // If A is symmetric, then compute the symbolic Cholesky + // factorization of A(ordering, ordering). If A is unsymmetric, then + // compute the symbolic factorization of + // A(ordering,:) A(ordering,:)'. + // + // A is not modified, only the pattern of non-zeros of A is used, + // the actual numerical values in A are of no consequence. + // + // Caller owns the result. + cholmod_factor* AnalyzeCholeskyWithUserOrdering(cholmod_sparse* A, + const vector& ordering); + // Use the symbolic factorization in L, to find the numerical // factorization for the matrix A or AA^T. Return true if // successful, false otherwise. L contains the numeric factorization @@ -129,6 +153,56 @@ class SuiteSparse { cholmod_factor* L, cholmod_dense* b); + // By virtue of the modeling layer in Ceres being block oriented, + // all the matrices used by Ceres are also block oriented. When + // doing sparse direct factorization of these matrices the + // fill-reducing ordering algorithms (in particular AMD) can either + // be run on the block or the scalar form of these matrices. The two + // SuiteSparse::AnalyzeCholesky methods allows the the client to + // compute the symbolic factorization of a matrix by either using + // AMD on the matrix or a user provided ordering of the rows. + // + // But since the underlying matrices are block oriented, it is worth + // running AMD on just the block structre of these matrices and then + // lifting these block orderings to a full scalar ordering. This + // preserves the block structure of the permuted matrix, and exposes + // more of the super-nodal structure of the matrix to the numerical + // factorization routines. + // + // Find the block oriented AMD ordering of a matrix A, whose row and + // column blocks are given by row_blocks, and col_blocks + // respectively. The matrix may or may not be symmetric. The entries + // of col_blocks do not need to sum to the number of columns in + // A. If this is the case, only the first sum(col_blocks) are used + // to compute the ordering. + bool BlockAMDOrdering(const cholmod_sparse* A, + const vector& row_blocks, + const vector& col_blocks, + vector* ordering); + + // Given a set of blocks and a permutation of these blocks, compute + // the corresponding "scalar" ordering, where the scalar ordering of + // size sum(blocks). + static void BlockOrderingToScalarOrdering(const vector& blocks, + const vector& block_ordering, + vector* scalar_ordering); + + // Extract the block sparsity pattern of the scalar sparse matrix + // A and return it in compressed column form. The compressed column + // form is stored in two vectors block_rows, and block_cols, which + // correspond to the row and column arrays in a compressed column sparse + // matrix. + // + // If c_ij is the block in the matrix A corresponding to row block i + // and column block j, then it is expected that A contains at least + // one non-zero entry corresponding to the top left entry of c_ij, + // as that entry is used to detect the presence of a non-zero c_ij. + static void ScalarMatrixToBlockMatrix(const cholmod_sparse* A, + const vector& row_blocks, + const vector& col_blocks, + vector* block_rows, + vector* block_cols); + void Free(cholmod_sparse* m) { cholmod_free_sparse(&m, &cc_); } void Free(cholmod_dense* m) { cholmod_free_dense(&m, &cc_); } void Free(cholmod_factor* m) { cholmod_free_factor(&m, &cc_); } diff --git a/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc index 247ab2e697b..ed8677ea18a 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc @@ -32,12 +32,12 @@ #include #include -#include -#include "ceres/matrix_proto.h" #include "ceres/internal/eigen.h" #include "ceres/internal/port.h" #include "ceres/internal/scoped_ptr.h" +#include "ceres/matrix_proto.h" #include "ceres/types.h" +#include "glog/logging.h" namespace ceres { namespace internal { @@ -82,7 +82,7 @@ TripletSparseMatrix::TripletSparseMatrix(const TripletSparseMatrix& orig) CopyData(orig); } -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS TripletSparseMatrix::TripletSparseMatrix(const SparseMatrixProto& outer_proto) { CHECK(outer_proto.has_triplet_matrix()); @@ -130,7 +130,7 @@ bool TripletSparseMatrix::AllTripletsWithinBounds() const { void TripletSparseMatrix::Reserve(int new_max_num_nonzeros) { CHECK_LE(num_nonzeros_, new_max_num_nonzeros) - << "Reallocation will cause data loss"; + << "Reallocation will cause data loss"; // Nothing to do if we have enough space already. if (new_max_num_nonzeros <= max_num_nonzeros_) @@ -214,7 +214,7 @@ void TripletSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const { } } -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS void TripletSparseMatrix::ToProto(SparseMatrixProto *proto) const { proto->Clear(); diff --git a/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.h index 300e74d0bbc..89a645bd879 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.h +++ b/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.h @@ -50,7 +50,7 @@ class TripletSparseMatrix : public SparseMatrix { TripletSparseMatrix(); TripletSparseMatrix(int num_rows, int num_cols, int max_num_nonzeros); explicit TripletSparseMatrix(const TripletSparseMatrix& orig); -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS explicit TripletSparseMatrix(const SparseMatrixProto& proto); #endif @@ -65,7 +65,7 @@ class TripletSparseMatrix : public SparseMatrix { virtual void SquaredColumnNorm(double* x) const; virtual void ScaleColumns(const double* scale); virtual void ToDenseMatrix(Matrix* dense_matrix) const; -#ifndef CERES_DONT_HAVE_PROTOCOL_BUFFERS +#ifndef CERES_NO_PROTOCOL_BUFFERS virtual void ToProto(SparseMatrixProto *proto) const; #endif virtual void ToTextFile(FILE* file) const; diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc b/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc new file mode 100644 index 00000000000..76c4f8a7580 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc @@ -0,0 +1,550 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#include "ceres/trust_region_minimizer.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "Eigen/Core" +#include "ceres/array_utils.h" +#include "ceres/evaluator.h" +#include "ceres/internal/eigen.h" +#include "ceres/internal/scoped_ptr.h" +#include "ceres/linear_least_squares_problems.h" +#include "ceres/sparse_matrix.h" +#include "ceres/trust_region_strategy.h" +#include "ceres/types.h" +#include "glog/logging.h" + +namespace ceres { +namespace internal { +namespace { +// Small constant for various floating point issues. +const double kEpsilon = 1e-12; +} // namespace + +// Execute the list of IterationCallbacks sequentially. If any one of +// the callbacks does not return SOLVER_CONTINUE, then stop and return +// its status. +CallbackReturnType TrustRegionMinimizer::RunCallbacks( + const IterationSummary& iteration_summary) { + for (int i = 0; i < options_.callbacks.size(); ++i) { + const CallbackReturnType status = + (*options_.callbacks[i])(iteration_summary); + if (status != SOLVER_CONTINUE) { + return status; + } + } + return SOLVER_CONTINUE; +} + +// Compute a scaling vector that is used to improve the conditioning +// of the Jacobian. +void TrustRegionMinimizer::EstimateScale(const SparseMatrix& jacobian, + double* scale) const { + jacobian.SquaredColumnNorm(scale); + for (int i = 0; i < jacobian.num_cols(); ++i) { + scale[i] = 1.0 / (kEpsilon + sqrt(scale[i])); + } +} + +void TrustRegionMinimizer::Init(const Minimizer::Options& options) { + options_ = options; + sort(options_.lsqp_iterations_to_dump.begin(), + options_.lsqp_iterations_to_dump.end()); +} + +bool TrustRegionMinimizer::MaybeDumpLinearLeastSquaresProblem( + const int iteration, + const SparseMatrix* jacobian, + const double* residuals, + const double* step) const { + // TODO(sameeragarwal): Since the use of trust_region_radius has + // moved inside TrustRegionStrategy, its not clear how we dump the + // regularization vector/matrix anymore. + // + // Doing this right requires either an API change to the + // TrustRegionStrategy and/or how LinearLeastSquares problems are + // stored on disk. + // + // For now, we will just not dump the regularizer. + return (!binary_search(options_.lsqp_iterations_to_dump.begin(), + options_.lsqp_iterations_to_dump.end(), + iteration) || + DumpLinearLeastSquaresProblem(options_.lsqp_dump_directory, + iteration, + options_.lsqp_dump_format_type, + jacobian, + NULL, + residuals, + step, + options_.num_eliminate_blocks)); +} + +void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, + double* parameters, + Solver::Summary* summary) { + time_t start_time = time(NULL); + time_t iteration_start_time = start_time; + Init(options); + + summary->termination_type = NO_CONVERGENCE; + summary->num_successful_steps = 0; + summary->num_unsuccessful_steps = 0; + + Evaluator* evaluator = CHECK_NOTNULL(options_.evaluator); + SparseMatrix* jacobian = CHECK_NOTNULL(options_.jacobian); + TrustRegionStrategy* strategy = CHECK_NOTNULL(options_.trust_region_strategy); + + const int num_parameters = evaluator->NumParameters(); + const int num_effective_parameters = evaluator->NumEffectiveParameters(); + const int num_residuals = evaluator->NumResiduals(); + + VectorRef x_min(parameters, num_parameters); + Vector x = x_min; + double x_norm = x.norm(); + + Vector residuals(num_residuals); + Vector trust_region_step(num_effective_parameters); + Vector delta(num_effective_parameters); + Vector x_plus_delta(num_parameters); + Vector gradient(num_effective_parameters); + Vector model_residuals(num_residuals); + Vector scale(num_effective_parameters); + + IterationSummary iteration_summary; + iteration_summary.iteration = 0; + iteration_summary.step_is_valid = false; + iteration_summary.step_is_successful = false; + iteration_summary.cost = summary->initial_cost; + iteration_summary.cost_change = 0.0; + iteration_summary.gradient_max_norm = 0.0; + iteration_summary.step_norm = 0.0; + iteration_summary.relative_decrease = 0.0; + iteration_summary.trust_region_radius = strategy->Radius(); + // TODO(sameeragarwal): Rename eta to linear_solver_accuracy or + // something similar across the board. + iteration_summary.eta = options_.eta; + iteration_summary.linear_solver_iterations = 0; + iteration_summary.step_solver_time_in_seconds = 0; + + // Do initial cost and Jacobian evaluation. + double cost = 0.0; + if (!evaluator->Evaluate(x.data(), &cost, residuals.data(), NULL, jacobian)) { + LOG(WARNING) << "Terminating: Residual and Jacobian evaluation failed."; + summary->termination_type = NUMERICAL_FAILURE; + return; + } + + int num_consecutive_nonmonotonic_steps = 0; + double minimum_cost = cost; + double reference_cost = cost; + double accumulated_reference_model_cost_change = 0.0; + double candidate_cost = cost; + double accumulated_candidate_model_cost_change = 0.0; + + gradient.setZero(); + jacobian->LeftMultiply(residuals.data(), gradient.data()); + iteration_summary.gradient_max_norm = gradient.lpNorm(); + + if (options_.jacobi_scaling) { + EstimateScale(*jacobian, scale.data()); + jacobian->ScaleColumns(scale.data()); + } else { + scale.setOnes(); + } + + // The initial gradient max_norm is bounded from below so that we do + // not divide by zero. + const double gradient_max_norm_0 = + max(iteration_summary.gradient_max_norm, kEpsilon); + const double absolute_gradient_tolerance = + options_.gradient_tolerance * gradient_max_norm_0; + + if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) { + summary->termination_type = GRADIENT_TOLERANCE; + VLOG(1) << "Terminating: Gradient tolerance reached." + << "Relative gradient max norm: " + << iteration_summary.gradient_max_norm / gradient_max_norm_0 + << " <= " << options_.gradient_tolerance; + return; + } + + iteration_summary.iteration_time_in_seconds = + time(NULL) - iteration_start_time; + iteration_summary.cumulative_time_in_seconds = time(NULL) - start_time + + summary->preprocessor_time_in_seconds; + summary->iterations.push_back(iteration_summary); + + // Call the various callbacks. + switch (RunCallbacks(iteration_summary)) { + case SOLVER_TERMINATE_SUCCESSFULLY: + summary->termination_type = USER_SUCCESS; + VLOG(1) << "Terminating: User callback returned USER_SUCCESS."; + return; + case SOLVER_ABORT: + summary->termination_type = USER_ABORT; + VLOG(1) << "Terminating: User callback returned USER_ABORT."; + return; + case SOLVER_CONTINUE: + break; + default: + LOG(FATAL) << "Unknown type of user callback status"; + } + + int num_consecutive_invalid_steps = 0; + while (true) { + iteration_start_time = time(NULL); + if (iteration_summary.iteration >= options_.max_num_iterations) { + summary->termination_type = NO_CONVERGENCE; + VLOG(1) << "Terminating: Maximum number of iterations reached."; + break; + } + + const double total_solver_time = iteration_start_time - start_time + + summary->preprocessor_time_in_seconds; + if (total_solver_time >= options_.max_solver_time_in_seconds) { + summary->termination_type = NO_CONVERGENCE; + VLOG(1) << "Terminating: Maximum solver time reached."; + break; + } + + iteration_summary = IterationSummary(); + iteration_summary = summary->iterations.back(); + iteration_summary.iteration = summary->iterations.back().iteration + 1; + iteration_summary.step_is_valid = false; + iteration_summary.step_is_successful = false; + + const time_t strategy_start_time = time(NULL); + TrustRegionStrategy::PerSolveOptions per_solve_options; + per_solve_options.eta = options_.eta; + TrustRegionStrategy::Summary strategy_summary = + strategy->ComputeStep(per_solve_options, + jacobian, + residuals.data(), + trust_region_step.data()); + + iteration_summary.step_solver_time_in_seconds = + time(NULL) - strategy_start_time; + iteration_summary.linear_solver_iterations = + strategy_summary.num_iterations; + + if (!MaybeDumpLinearLeastSquaresProblem(iteration_summary.iteration, + jacobian, + residuals.data(), + trust_region_step.data())) { + LOG(FATAL) << "Tried writing linear least squares problem: " + << options.lsqp_dump_directory << "but failed."; + } + + double new_model_cost = 0.0; + if (strategy_summary.termination_type != FAILURE) { + // new_model_cost = 1/2 |f + J * step|^2 + model_residuals = residuals; + jacobian->RightMultiply(trust_region_step.data(), model_residuals.data()); + new_model_cost = model_residuals.squaredNorm() / 2.0; + + // In exact arithmetic, this would never be the case. But poorly + // conditioned matrices can give rise to situations where the + // new_model_cost can actually be larger than half the squared + // norm of the residual vector. We allow for small tolerance + // around cost and beyond that declare the step to be invalid. + if ((1.0 - new_model_cost / cost) < -kEpsilon) { + VLOG(1) << "Invalid step: current_cost: " << cost + << " new_model_cost " << new_model_cost + << " absolute difference " << (cost - new_model_cost) + << " relative difference " << (1.0 - new_model_cost/cost); + } else { + iteration_summary.step_is_valid = true; + } + } + + if (!iteration_summary.step_is_valid) { + // Invalid steps can happen due to a number of reasons, and we + // allow a limited number of successive failures, and return with + // NUMERICAL_FAILURE if this limit is exceeded. + if (++num_consecutive_invalid_steps >= + options_.max_num_consecutive_invalid_steps) { + summary->termination_type = NUMERICAL_FAILURE; + LOG(WARNING) << "Terminating. Number of successive invalid steps more " + << "than " + << "Solver::Options::max_num_consecutive_invalid_steps: " + << options_.max_num_consecutive_invalid_steps; + return; + } + + // We are going to try and reduce the trust region radius and + // solve again. To do this, we are going to treat this iteration + // as an unsuccessful iteration. Since the various callbacks are + // still executed, we are going to fill the iteration summary + // with data that assumes a step of length zero and no progress. + iteration_summary.cost = cost; + iteration_summary.cost_change = 0.0; + iteration_summary.gradient_max_norm = + summary->iterations.back().gradient_max_norm; + iteration_summary.step_norm = 0.0; + iteration_summary.relative_decrease = 0.0; + iteration_summary.eta = options_.eta; + } else { + // The step is numerically valid, so now we can judge its quality. + num_consecutive_invalid_steps = 0; + + // We allow some slop around 0, and clamp the model_cost_change + // at kEpsilon * min(1.0, cost) from below. + // + // In exact arithmetic this should never be needed, as we are + // guaranteed to new_model_cost <= cost. However, due to various + // numerical issues, it is possible that new_model_cost is + // nearly equal to cost, and the difference is a small negative + // number. To make sure that the relative_decrease computation + // remains sane, as clamp the difference (cost - new_model_cost) + // from below at a small positive number. + // + // This number is the minimum of kEpsilon * (cost, 1.0), which + // ensures that it will never get too large in absolute value, + // while scaling down proportionally with the magnitude of the + // cost. This is important for problems where the minimum of the + // objective function is near zero. + const double model_cost_change = + max(kEpsilon * min(1.0, cost), cost - new_model_cost); + + // Undo the Jacobian column scaling. + delta = (trust_region_step.array() * scale.array()).matrix(); + iteration_summary.step_norm = delta.norm(); + + // Convergence based on parameter_tolerance. + const double step_size_tolerance = options_.parameter_tolerance * + (x_norm + options_.parameter_tolerance); + if (iteration_summary.step_norm <= step_size_tolerance) { + VLOG(1) << "Terminating. Parameter tolerance reached. " + << "relative step_norm: " + << iteration_summary.step_norm / + (x_norm + options_.parameter_tolerance) + << " <= " << options_.parameter_tolerance; + summary->termination_type = PARAMETER_TOLERANCE; + return; + } + + if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) { + summary->termination_type = NUMERICAL_FAILURE; + LOG(WARNING) << "Terminating. Failed to compute " + << "Plus(x, delta, x_plus_delta)."; + return; + } + + // Try this step. + double new_cost; + if (!evaluator->Evaluate(x_plus_delta.data(), + &new_cost, + NULL, NULL, NULL)) { + // If the evaluation of the new cost fails, treat it as a step + // with high cost. + LOG(WARNING) << "Step failed to evaluate. " + << "Treating it as step with infinite cost"; + new_cost = numeric_limits::max(); + } + + VLOG(2) << "old cost: " << cost << " new cost: " << new_cost; + iteration_summary.cost_change = cost - new_cost; + const double absolute_function_tolerance = + options_.function_tolerance * cost; + if (fabs(iteration_summary.cost_change) < absolute_function_tolerance) { + VLOG(1) << "Terminating. Function tolerance reached. " + << "|cost_change|/cost: " + << fabs(iteration_summary.cost_change) / cost + << " <= " << options_.function_tolerance; + summary->termination_type = FUNCTION_TOLERANCE; + return; + } + + const double relative_decrease = + iteration_summary.cost_change / model_cost_change; + + const double historical_relative_decrease = + (reference_cost - new_cost) / + (accumulated_reference_model_cost_change + model_cost_change); + + // If monotonic steps are being used, then the relative_decrease + // is the usual ratio of the change in objective function value + // divided by the change in model cost. + // + // If non-monotonic steps are allowed, then we take the maximum + // of the relative_decrease and the + // historical_relative_decrease, which measures the increase + // from a reference iteration. The model cost change is + // estimated by accumulating the model cost changes since the + // reference iteration. The historical relative_decrease offers + // a boost to a step which is not too bad compared to the + // reference iteration, allowing for non-monotonic steps. + iteration_summary.relative_decrease = + options.use_nonmonotonic_steps + ? max(relative_decrease, historical_relative_decrease) + : relative_decrease; + + iteration_summary.step_is_successful = + iteration_summary.relative_decrease > options_.min_relative_decrease; + + if (iteration_summary.step_is_successful) { + accumulated_candidate_model_cost_change += model_cost_change; + accumulated_reference_model_cost_change += model_cost_change; + if (relative_decrease <= options_.min_relative_decrease) { + VLOG(2) << "Non-monotonic step! " + << " relative_decrease: " << relative_decrease + << " historical_relative_decrease: " + << historical_relative_decrease; + } + } + } + + if (iteration_summary.step_is_successful) { + ++summary->num_successful_steps; + strategy->StepAccepted(iteration_summary.relative_decrease); + x = x_plus_delta; + x_norm = x.norm(); + + // Step looks good, evaluate the residuals and Jacobian at this + // point. + if (!evaluator->Evaluate(x.data(), + &cost, + residuals.data(), + NULL, + jacobian)) { + summary->termination_type = NUMERICAL_FAILURE; + LOG(WARNING) << "Terminating: Residual and Jacobian evaluation failed."; + return; + } + + gradient.setZero(); + jacobian->LeftMultiply(residuals.data(), gradient.data()); + iteration_summary.gradient_max_norm = gradient.lpNorm(); + + if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) { + summary->termination_type = GRADIENT_TOLERANCE; + VLOG(1) << "Terminating: Gradient tolerance reached." + << "Relative gradient max norm: " + << iteration_summary.gradient_max_norm / gradient_max_norm_0 + << " <= " << options_.gradient_tolerance; + return; + } + + if (options_.jacobi_scaling) { + jacobian->ScaleColumns(scale.data()); + } + + // Update the best, reference and candidate iterates. + // + // Based on algorithm 10.1.2 (page 357) of "Trust Region + // Methods" by Conn Gould & Toint, or equations 33-40 of + // "Non-monotone trust-region algorithms for nonlinear + // optimization subject to convex constraints" by Phil Toint, + // Mathematical Programming, 77, 1997. + if (cost < minimum_cost) { + // A step that improves solution quality was found. + x_min = x; + minimum_cost = cost; + // Set the candidate iterate to the current point. + candidate_cost = cost; + num_consecutive_nonmonotonic_steps = 0; + accumulated_candidate_model_cost_change = 0.0; + } else { + ++num_consecutive_nonmonotonic_steps; + if (cost > candidate_cost) { + // The current iterate is has a higher cost than the + // candidate iterate. Set the candidate to this point. + VLOG(2) << "Updating the candidate iterate to the current point."; + candidate_cost = cost; + accumulated_candidate_model_cost_change = 0.0; + } + + // At this point we have made too many non-monotonic steps and + // we are going to reset the value of the reference iterate so + // as to force the algorithm to descend. + // + // This is the case because the candidate iterate has a value + // greater than minimum_cost but smaller than the reference + // iterate. + if (num_consecutive_nonmonotonic_steps == + options.max_consecutive_nonmonotonic_steps) { + VLOG(2) << "Resetting the reference point to the candidate point"; + reference_cost = candidate_cost; + accumulated_reference_model_cost_change = + accumulated_candidate_model_cost_change; + } + } + } else { + ++summary->num_unsuccessful_steps; + if (iteration_summary.step_is_valid) { + strategy->StepRejected(iteration_summary.relative_decrease); + } else { + strategy->StepIsInvalid(); + } + } + + iteration_summary.cost = cost + summary->fixed_cost; + iteration_summary.trust_region_radius = strategy->Radius(); + if (iteration_summary.trust_region_radius < + options_.min_trust_region_radius) { + summary->termination_type = PARAMETER_TOLERANCE; + VLOG(1) << "Termination. Minimum trust region radius reached."; + return; + } + + iteration_summary.iteration_time_in_seconds = + time(NULL) - iteration_start_time; + iteration_summary.cumulative_time_in_seconds = time(NULL) - start_time + + summary->preprocessor_time_in_seconds; + summary->iterations.push_back(iteration_summary); + + switch (RunCallbacks(iteration_summary)) { + case SOLVER_TERMINATE_SUCCESSFULLY: + summary->termination_type = USER_SUCCESS; + VLOG(1) << "Terminating: User callback returned USER_SUCCESS."; + return; + case SOLVER_ABORT: + summary->termination_type = USER_ABORT; + VLOG(1) << "Terminating: User callback returned USER_ABORT."; + return; + case SOLVER_CONTINUE: + break; + default: + LOG(FATAL) << "Unknown type of user callback status"; + } + } +} + + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h b/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h new file mode 100644 index 00000000000..a4f5ba3674d --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h @@ -0,0 +1,67 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#ifndef CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_ +#define CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_ + +#include "ceres/minimizer.h" +#include "ceres/solver.h" +#include "ceres/types.h" + +namespace ceres { +namespace internal { + +// Generic trust region minimization algorithm. The heavy lifting is +// done by a TrustRegionStrategy object passed in as one of the +// arguments to the Minimize method. +// +// For example usage, see SolverImpl::Minimize. +class TrustRegionMinimizer : public Minimizer { + public: + ~TrustRegionMinimizer() {} + virtual void Minimize(const Minimizer::Options& options, + double* parameters, + Solver::Summary* summary); + + private: + void Init(const Minimizer::Options& options); + void EstimateScale(const SparseMatrix& jacobian, double* scale) const; + CallbackReturnType RunCallbacks(const IterationSummary& iteration_summary); + bool MaybeDumpLinearLeastSquaresProblem( const int iteration, + const SparseMatrix* jacobian, + const double* residuals, + const double* step) const; + + Minimizer::Options options_; +}; + +} // namespace internal +} // namespace ceres +#endif // CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc b/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc new file mode 100644 index 00000000000..89bc19d084b --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc @@ -0,0 +1,27 @@ +#include "ceres/trust_region_strategy.h" +#include "ceres/dogleg_strategy.h" +#include "ceres/levenberg_marquardt_strategy.h" + +namespace ceres { +namespace internal { + +TrustRegionStrategy::~TrustRegionStrategy() {} + +TrustRegionStrategy* TrustRegionStrategy::Create(const Options& options) { + switch (options.trust_region_strategy_type) { + case LEVENBERG_MARQUARDT: + return new LevenbergMarquardtStrategy(options); + case DOGLEG: + return new DoglegStrategy(options); + default: + LOG(FATAL) << "Unknown trust region strategy: " + << options.trust_region_strategy_type; + } + + LOG(FATAL) << "Unknown trust region strategy: " + << options.trust_region_strategy_type; + return NULL; +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h b/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h new file mode 100644 index 00000000000..391da97d5eb --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h @@ -0,0 +1,148 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#ifndef CERES_INTERNAL_TRUST_REGION_STRATEGY_H_ +#define CERES_INTERNAL_TRUST_REGION_STRATEGY_H_ + +#include "ceres/types.h" + +namespace ceres { +namespace internal { + +class LinearSolver; +class SparseMatrix; + +// Interface for classes implementing various trust region strategies +// for nonlinear least squares problems. +// +// The object is expected to maintain and update a trust region +// radius, which it then uses to solve for the trust region step using +// the jacobian matrix and residual vector. +// +// Here the term trust region radius is used loosely, as the strategy +// is free to treat it as guidance and violate it as need be. e.g., +// the LevenbergMarquardtStrategy uses the inverse of the trust region +// radius to scale the damping term, which controls the step size, but +// does not set a hard limit on its size. +class TrustRegionStrategy { +public: + struct Options { + Options() + : trust_region_strategy_type(LEVENBERG_MARQUARDT), + initial_radius(1e4), + max_radius(1e32), + lm_min_diagonal(1e-6), + lm_max_diagonal(1e32), + dogleg_type(TRADITIONAL_DOGLEG) { + } + + TrustRegionStrategyType trust_region_strategy_type; + // Linear solver used for actually solving the trust region step. + LinearSolver* linear_solver; + double initial_radius; + double max_radius; + + // Minimum and maximum values of the diagonal damping matrix used + // by LevenbergMarquardtStrategy. The DoglegStrategy also uses + // these bounds to construct a regularizing diagonal to ensure + // that the Gauss-Newton step computation is of full rank. + double lm_min_diagonal; + double lm_max_diagonal; + + // Further specify which dogleg method to use + DoglegType dogleg_type; + }; + + // Per solve options. + struct PerSolveOptions { + // Forcing sequence for inexact solves. + double eta; + }; + + struct Summary { + Summary() + : residual_norm(0.0), + num_iterations(-1), + termination_type(FAILURE) { + } + + // If the trust region problem is, + // + // 1/2 x'Ax + b'x + c, + // + // then + // + // residual_norm = |Ax -b| + double residual_norm; + + // Number of iterations used by the linear solver. If a linear + // solver was not called (e.g., DogLegStrategy after an + // unsuccessful step), then this would be zero. + int num_iterations; + + // Status of the linear solver used to solve the Newton system. + LinearSolverTerminationType termination_type; + }; + + virtual ~TrustRegionStrategy(); + + // Use the current radius to solve for the trust region step. + virtual Summary ComputeStep(const PerSolveOptions& per_solve_options, + SparseMatrix* jacobian, + const double* residuals, + double* step) = 0; + + // Inform the strategy that the current step has been accepted, and + // that the ratio of the decrease in the non-linear objective to the + // decrease in the trust region model is step_quality. + virtual void StepAccepted(double step_quality) = 0; + + // Inform the strategy that the current step has been rejected, and + // that the ratio of the decrease in the non-linear objective to the + // decrease in the trust region model is step_quality. + virtual void StepRejected(double step_quality) = 0; + + // Inform the strategy that the current step has been rejected + // because it was found to be numerically invalid. + // StepRejected/StepAccepted will not be called for this step, and + // the strategy is free to do what it wants with this information. + virtual void StepIsInvalid() = 0; + + // Current trust region radius. + virtual double Radius() const = 0; + + // Factory. + static TrustRegionStrategy* Create(const Options& options); +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_TRUST_REGION_STRATEGY_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/types.cc b/extern/libmv/third_party/ceres/internal/ceres/types.cc index 860f8a43f37..05e573ff6d5 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/types.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/types.cc @@ -37,8 +37,9 @@ namespace ceres { const char* LinearSolverTypeToString(LinearSolverType solver_type) { switch (solver_type) { - CASESTR(SPARSE_NORMAL_CHOLESKY); + CASESTR(DENSE_NORMAL_CHOLESKY); CASESTR(DENSE_QR); + CASESTR(SPARSE_NORMAL_CHOLESKY); CASESTR(DENSE_SCHUR); CASESTR(SPARSE_SCHUR); CASESTR(ITERATIVE_SCHUR); @@ -61,6 +62,16 @@ const char* PreconditionerTypeToString( } } +const char* SparseLinearAlgebraLibraryTypeToString( + SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type) { + switch (sparse_linear_algebra_library_type) { + CASESTR(SUITE_SPARSE); + CASESTR(CX_SPARSE); + default: + return "UNKNOWN"; + } +} + const char* OrderingTypeToString(OrderingType ordering_type) { switch (ordering_type) { CASESTR(NATURAL); @@ -87,6 +98,28 @@ const char* SolverTerminationTypeToString( } } +#if 0 /* UNUSED */ +static const char* SparseLinearAlgebraTypeToString( + SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type) { + switch (sparse_linear_algebra_library_type) { + CASESTR(CX_SPARSE); + CASESTR(SUITE_SPARSE); + default: + return "UNKNOWN"; + } +} +#endif + +const char* TrustRegionStrategyTypeToString( + TrustRegionStrategyType trust_region_strategy_type) { + switch (trust_region_strategy_type) { + CASESTR(LEVENBERG_MARQUARDT); + CASESTR(DOGLEG); + default: + return "UNKNOWN"; + } +} + #undef CASESTR bool IsSchurType(LinearSolverType type) { diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility.cc b/extern/libmv/third_party/ceres/internal/ceres/visibility.cc index fd41648a7af..564cc54493e 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/visibility.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/visibility.cc @@ -34,11 +34,11 @@ #include #include #include - -#include #include "ceres/block_structure.h" #include "ceres/collections_port.h" +#include "ceres/visibility.h" #include "ceres/graph.h" +#include "glog/logging.h" namespace ceres { namespace internal { diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc b/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc index aca77528215..4caad03d7a1 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc @@ -33,11 +33,9 @@ #include #include #include -#include #include #include #include -#include #include "Eigen/Dense" #include "ceres/block_random_access_sparse_matrix.h" #include "ceres/block_sparse_matrix.h" @@ -46,10 +44,11 @@ #include "ceres/detect_structure.h" #include "ceres/graph.h" #include "ceres/graph_algorithms.h" +#include "ceres/internal/scoped_ptr.h" #include "ceres/linear_solver.h" #include "ceres/schur_eliminator.h" #include "ceres/visibility.h" -#include "ceres/internal/scoped_ptr.h" +#include "glog/logging.h" namespace ceres { namespace internal { @@ -253,7 +252,6 @@ void VisibilityBasedPreconditioner::ComputeBlockPairsInPreconditioner( } int r = 0; - set > skipped_pairs; const int num_row_blocks = bs.rows.size(); const int num_eliminate_blocks = options_.num_eliminate_blocks; @@ -304,8 +302,6 @@ void VisibilityBasedPreconditioner::ComputeBlockPairsInPreconditioner( for (; block2 != f_blocks.end(); ++block2) { if (IsBlockPairInPreconditioner(*block1, *block2)) { block_pairs_.insert(make_pair(*block1, *block2)); - } else { - skipped_pairs.insert(make_pair(*block1, *block2)); } } } @@ -322,17 +318,13 @@ void VisibilityBasedPreconditioner::ComputeBlockPairsInPreconditioner( if (block1 <= block2) { if (IsBlockPairInPreconditioner(block1, block2)) { block_pairs_.insert(make_pair(block1, block2)); - } else { - skipped_pairs.insert(make_pair(block1, block2)); } } } } } - VLOG(1) << "Block pair stats: " - << block_pairs_.size() << " included " - << skipped_pairs.size() << " excluded"; + VLOG(1) << "Block pair stats: " << block_pairs_.size(); } // Initialize the SchurEliminator. @@ -341,7 +333,6 @@ void VisibilityBasedPreconditioner::InitEliminator( LinearSolver::Options eliminator_options; eliminator_options.num_eliminate_blocks = options_.num_eliminate_blocks; eliminator_options.num_threads = options_.num_threads; - eliminator_options.constant_sparsity = true; DetectStructure(bs, options_.num_eliminate_blocks, &eliminator_options.row_block_size, @@ -352,9 +343,9 @@ void VisibilityBasedPreconditioner::InitEliminator( eliminator_->Init(options_.num_eliminate_blocks, &bs); } -// Compute the values of the preconditioner matrix and factorize it. -bool VisibilityBasedPreconditioner::Compute(const BlockSparseMatrixBase& A, - const double* D) { +// Update the values of the preconditioner matrix and factorize it. +bool VisibilityBasedPreconditioner::Update(const BlockSparseMatrixBase& A, + const double* D) { const time_t start_time = time(NULL); const int num_rows = m_->num_rows(); CHECK_GT(num_rows, 0); @@ -448,12 +439,21 @@ bool VisibilityBasedPreconditioner::Factorize() { // matrix contains the values. lhs->stype = 1; - // Symbolic factorization is computed if we don't already have one - // handy. + // Symbolic factorization is computed if we don't already have one handy. if (factor_ == NULL) { - factor_ = ss_.AnalyzeCholesky(lhs); + if (options_.use_block_amd) { + factor_ = ss_.BlockAnalyzeCholesky(lhs, block_size_, block_size_); + } else { + factor_ = ss_.AnalyzeCholesky(lhs); + } + + if (VLOG_IS_ON(2)) { + cholmod_print_common("Symbolic Analysis", ss_.mutable_cc()); + } } + CHECK_NOTNULL(factor_); + bool status = ss_.Cholesky(lhs, factor_); ss_.Free(lhs); return status; diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h b/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h index fa095ca1dd8..888c65eba3a 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h +++ b/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h @@ -133,7 +133,7 @@ class SchurEliminatorBase; // options.num_eliminate_blocks = num_points; // VisibilityBasedPreconditioner preconditioner( // *A.block_structure(), options); -// preconditioner.Compute(A, NULL); +// preconditioner.Update(A, NULL); // preconditioner.RightMultiply(x, y); // @@ -160,7 +160,7 @@ class VisibilityBasedPreconditioner : public LinearOperator { const LinearSolver::Options& options); virtual ~VisibilityBasedPreconditioner(); - // Compute the numerical value of the preconditioner for the linear + // Update the numerical value of the preconditioner for the linear // system: // // | A | x = |b| @@ -171,12 +171,12 @@ class VisibilityBasedPreconditioner : public LinearOperator { // // D can be NULL, in which case its interpreted as a diagonal matrix // of size zero. - bool Compute(const BlockSparseMatrixBase& A, - const double* D); + bool Update(const BlockSparseMatrixBase& A, const double* D); + // LinearOperator interface. Since the operator is symmetric, // LeftMultiply and num_cols are just calls to RightMultiply and - // num_rows respectively. Compute() must be called before + // num_rows respectively. Update() must be called before // RightMultiply can be called. virtual void RightMultiply(const double* x, double* y) const; virtual void LeftMultiply(const double* x, double* y) const { @@ -244,7 +244,7 @@ class VisibilityBasedPreconditioner : public LinearOperator { // Temporary vector used by RightMultiply. cholmod_dense* tmp_rhs_; - DISALLOW_COPY_AND_ASSIGN(VisibilityBasedPreconditioner); + CERES_DISALLOW_COPY_AND_ASSIGN(VisibilityBasedPreconditioner); }; #else // SuiteSparse // If SuiteSparse is not compiled in, the preconditioner is not @@ -261,7 +261,7 @@ class VisibilityBasedPreconditioner : public LinearOperator { virtual void LeftMultiply(const double* x, double* y) const {} virtual int num_rows() const { return -1; } virtual int num_cols() const { return -1; } - bool Compute(const BlockSparseMatrixBase& A, const double* D) { + bool Update(const BlockSparseMatrixBase& A, const double* D) { return false; } }; diff --git a/extern/libmv/third_party/ceres/patches/collections_port.h.mingw.patch b/extern/libmv/third_party/ceres/patches/collections_port.h.mingw.patch index bbb366e22bc..c01a17c7992 100644 --- a/extern/libmv/third_party/ceres/patches/collections_port.h.mingw.patch +++ b/extern/libmv/third_party/ceres/patches/collections_port.h.mingw.patch @@ -1,10 +1,10 @@ -Index: internal/ceres/collections_port.h -=================================================================== ---- internal/ceres/collections_port.h (revision 47730) -+++ internal/ceres/collections_port.h (working copy) -@@ -53,7 +53,7 @@ +diff --git a/internal/ceres/collections_port.h b/internal/ceres/collections_port.h +index a356cc0..c2fce90 100644 +--- a/internal/ceres/collections_port.h ++++ b/internal/ceres/collections_port.h +@@ -77,7 +77,7 @@ struct HashMap : std::tr1::unordered_map {}; template - struct HashSet : tr1::unordered_set {}; + struct HashSet : std::tr1::unordered_set {}; -#ifdef _WIN32 +#if defined(_WIN32) && !defined(__MINGW64__) && !defined(__MINGW32__) diff --git a/extern/libmv/third_party/ceres/patches/msvc_glog_fix.patch b/extern/libmv/third_party/ceres/patches/msvc_glog_fix.patch new file mode 100644 index 00000000000..f3200fb8e0a --- /dev/null +++ b/extern/libmv/third_party/ceres/patches/msvc_glog_fix.patch @@ -0,0 +1,50 @@ +diff --git a/internal/ceres/block_random_access_dense_matrix.cc b/internal/ceres/block_random_access_dense_matrix.cc +index aedfc74..0f95e89 100644 +--- a/internal/ceres/block_random_access_dense_matrix.cc ++++ b/internal/ceres/block_random_access_dense_matrix.cc +@@ -28,12 +28,12 @@ + // + // Author: sameeragarwal@google.com (Sameer Agarwal) + ++#include "glog/logging.h" + #include "ceres/block_random_access_dense_matrix.h" + + #include + #include "ceres/internal/eigen.h" + #include "ceres/internal/scoped_ptr.h" +-#include "glog/logging.h" + + namespace ceres { + namespace internal { +diff --git a/internal/ceres/block_random_access_sparse_matrix.cc b/internal/ceres/block_random_access_sparse_matrix.cc +index f789436..9ed62ce 100644 +--- a/internal/ceres/block_random_access_sparse_matrix.cc ++++ b/internal/ceres/block_random_access_sparse_matrix.cc +@@ -28,6 +28,7 @@ + // + // Author: sameeragarwal@google.com (Sameer Agarwal) + ++#include "glog/logging.h" + #include "ceres/block_random_access_sparse_matrix.h" + + #include +@@ -39,7 +40,6 @@ + #include "ceres/mutex.h" + #include "ceres/triplet_sparse_matrix.h" + #include "ceres/types.h" +-#include "glog/logging.h" + + namespace ceres { + namespace internal { +diff --git a/internal/ceres/schur_complement_solver.cc b/internal/ceres/schur_complement_solver.cc +index b9224d8..2cbe78d 100644 +--- a/internal/ceres/schur_complement_solver.cc ++++ b/internal/ceres/schur_complement_solver.cc +@@ -38,6 +38,7 @@ + #endif // CERES_NO_CXSPARSE + + #include "Eigen/Dense" ++#include "glog/logging.h" + #include "ceres/block_random_access_dense_matrix.h" + #include "ceres/block_random_access_matrix.h" + #include "ceres/block_random_access_sparse_matrix.h" diff --git a/extern/libmv/third_party/ceres/patches/msvc_isfinite.patch b/extern/libmv/third_party/ceres/patches/msvc_isfinite.patch deleted file mode 100644 index c3129d8e02b..00000000000 --- a/extern/libmv/third_party/ceres/patches/msvc_isfinite.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/internal/ceres/residual_block_utils.cc b/internal/ceres/residual_block_utils.cc -index ed3499b..28e0313 100644 ---- a/internal/ceres/residual_block_utils.cc -+++ b/internal/ceres/residual_block_utils.cc -@@ -40,6 +40,10 @@ - #include "ceres/internal/eigen.h" - #include "ceres/internal/port.h" - -+#ifdef _MSC_VER -+# define isfinite _finite -+#endif -+ - namespace ceres { - namespace internal { - diff --git a/extern/libmv/third_party/ceres/patches/no_previous_declaration_fix.patch b/extern/libmv/third_party/ceres/patches/no_previous_declaration_fix.patch new file mode 100644 index 00000000000..03f1c500d9a --- /dev/null +++ b/extern/libmv/third_party/ceres/patches/no_previous_declaration_fix.patch @@ -0,0 +1,199 @@ +diff --git a/internal/ceres/file.cc b/internal/ceres/file.cc +index 387f359..6fe7557 100644 +--- a/internal/ceres/file.cc ++++ b/internal/ceres/file.cc +@@ -31,6 +31,7 @@ + // Really simple file IO. + + #include ++#include "file.h" + #include "glog/logging.h" + + namespace ceres { +diff --git a/internal/ceres/linear_least_squares_problems.cc b/internal/ceres/linear_least_squares_problems.cc +index 3e3bcd0..a91e254 100644 +--- a/internal/ceres/linear_least_squares_problems.cc ++++ b/internal/ceres/linear_least_squares_problems.cc +@@ -573,13 +573,13 @@ LinearLeastSquaresProblem* LinearLeastSquaresProblem3() { + return problem; + } + +-bool DumpLinearLeastSquaresProblemToConsole(const string& directory, +- int iteration, +- const SparseMatrix* A, +- const double* D, +- const double* b, +- const double* x, +- int num_eliminate_blocks) { ++static bool DumpLinearLeastSquaresProblemToConsole(const string& directory, ++ int iteration, ++ const SparseMatrix* A, ++ const double* D, ++ const double* b, ++ const double* x, ++ int num_eliminate_blocks) { + CHECK_NOTNULL(A); + Matrix AA; + A->ToDenseMatrix(&AA); +@@ -601,13 +601,13 @@ bool DumpLinearLeastSquaresProblemToConsole(const string& directory, + }; + + #ifndef CERES_NO_PROTOCOL_BUFFERS +-bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, +- int iteration, +- const SparseMatrix* A, +- const double* D, +- const double* b, +- const double* x, +- int num_eliminate_blocks) { ++static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, ++ int iteration, ++ const SparseMatrix* A, ++ const double* D, ++ const double* b, ++ const double* x, ++ int num_eliminate_blocks) { + CHECK_NOTNULL(A); + LinearLeastSquaresProblemProto lsqp; + A->ToProto(lsqp.mutable_a()); +@@ -641,13 +641,13 @@ bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, + return true; + } + #else +-bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, +- int iteration, +- const SparseMatrix* A, +- const double* D, +- const double* b, +- const double* x, +- int num_eliminate_blocks) { ++static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, ++ int iteration, ++ const SparseMatrix* A, ++ const double* D, ++ const double* b, ++ const double* x, ++ int num_eliminate_blocks) { + LOG(ERROR) << "Dumping least squares problems is only " + << "supported when Ceres is compiled with " + << "protocol buffer support."; +@@ -655,9 +655,9 @@ bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, + } + #endif + +-void WriteArrayToFileOrDie(const string& filename, +- const double* x, +- const int size) { ++static void WriteArrayToFileOrDie(const string& filename, ++ const double* x, ++ const int size) { + CHECK_NOTNULL(x); + VLOG(2) << "Writing array to: " << filename; + FILE* fptr = fopen(filename.c_str(), "w"); +@@ -668,13 +668,13 @@ void WriteArrayToFileOrDie(const string& filename, + fclose(fptr); + } + +-bool DumpLinearLeastSquaresProblemToTextFile(const string& directory, +- int iteration, +- const SparseMatrix* A, +- const double* D, +- const double* b, +- const double* x, +- int num_eliminate_blocks) { ++static bool DumpLinearLeastSquaresProblemToTextFile(const string& directory, ++ int iteration, ++ const SparseMatrix* A, ++ const double* D, ++ const double* b, ++ const double* x, ++ int num_eliminate_blocks) { + CHECK_NOTNULL(A); + string format_string = JoinPath(directory, + "lm_iteration_%03d"); +diff --git a/internal/ceres/residual_block_utils.cc b/internal/ceres/residual_block_utils.cc +index ff18e21..9442bb2 100644 +--- a/internal/ceres/residual_block_utils.cc ++++ b/internal/ceres/residual_block_utils.cc +@@ -63,7 +63,7 @@ void InvalidateEvaluation(const ResidualBlock& block, + + // Utility routine to print an array of doubles to a string. If the + // array pointer is NULL, it is treated as an array of zeros. +-void AppendArrayToString(const int size, const double* x, string* result) { ++static void AppendArrayToString(const int size, const double* x, string* result) { + for (int i = 0; i < size; ++i) { + if (x == NULL) { + StringAppendF(result, "Not Computed "); +diff --git a/internal/ceres/solver_impl.cc b/internal/ceres/solver_impl.cc +index 2802a75..8ef5b98 100644 +--- a/internal/ceres/solver_impl.cc ++++ b/internal/ceres/solver_impl.cc +@@ -685,8 +685,8 @@ bool SolverImpl::ApplyUserOrdering(const ProblemImpl& problem_impl, + // Find the minimum index of any parameter block to the given residual. + // Parameter blocks that have indices greater than num_eliminate_blocks are + // considered to have an index equal to num_eliminate_blocks. +-int MinParameterBlock(const ResidualBlock* residual_block, +- int num_eliminate_blocks) { ++static int MinParameterBlock(const ResidualBlock* residual_block, ++ int num_eliminate_blocks) { + int min_parameter_block_position = num_eliminate_blocks; + for (int i = 0; i < residual_block->NumParameterBlocks(); ++i) { + ParameterBlock* parameter_block = residual_block->parameter_blocks()[i]; +diff --git a/internal/ceres/split.cc b/internal/ceres/split.cc +index 4fa1bd4..c65c8a5 100644 +--- a/internal/ceres/split.cc ++++ b/internal/ceres/split.cc +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include "ceres/split.h" + #include "ceres/internal/port.h" + + namespace ceres { +diff --git a/internal/ceres/stringprintf.cc b/internal/ceres/stringprintf.cc +index c0f3522..396a48b 100644 +--- a/internal/ceres/stringprintf.cc ++++ b/internal/ceres/stringprintf.cc +@@ -34,6 +34,7 @@ + #include + #include + ++#include "ceres/stringprintf.h" + #include "ceres/internal/port.h" + + namespace ceres { +diff --git a/internal/ceres/types.cc b/internal/ceres/types.cc +index 2e950c5..05e573f 100644 +--- a/internal/ceres/types.cc ++++ b/internal/ceres/types.cc +@@ -98,7 +98,8 @@ const char* SolverTerminationTypeToString( + } + } + +-const char* SparseLinearAlgebraTypeToString( ++#if 0 /* UNUSED */ ++static const char* SparseLinearAlgebraTypeToString( + SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type) { + switch (sparse_linear_algebra_library_type) { + CASESTR(CX_SPARSE); +@@ -107,6 +108,7 @@ const char* SparseLinearAlgebraTypeToString( + return "UNKNOWN"; + } + } ++#endif + + const char* TrustRegionStrategyTypeToString( + TrustRegionStrategyType trust_region_strategy_type) { +diff --git a/internal/ceres/visibility.cc b/internal/ceres/visibility.cc +index 9d80654..564cc54 100644 +--- a/internal/ceres/visibility.cc ++++ b/internal/ceres/visibility.cc +@@ -36,6 +36,7 @@ + #include + #include "ceres/block_structure.h" + #include "ceres/collections_port.h" ++#include "ceres/visibility.h" + #include "ceres/graph.h" + #include "glog/logging.h" + diff --git a/extern/libmv/third_party/ceres/patches/series b/extern/libmv/third_party/ceres/patches/series index dbe955ae61e..a6874318923 100644 --- a/extern/libmv/third_party/ceres/patches/series +++ b/extern/libmv/third_party/ceres/patches/series @@ -1 +1,3 @@ -msvc_isfinite.patch +collections_port.h.mingw.patch +msvc_glog_fix.patch +no_previous_declaration_fix.patch \ No newline at end of file diff --git a/extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp b/extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp index 130c08ec369..b52da597675 100644 --- a/extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp +++ b/extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp @@ -1015,7 +1015,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa maxhh = rcMax(maxhh, ymax-ymin); } - hp.data = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxhw*maxhh, RC_ALLOC_TEMP); + hp.data = (unsigned short *)rcAlloc(sizeof(unsigned short)*maxhw*maxhh, RC_ALLOC_TEMP); if (!hp.data) { ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'hp.data' (%d).", maxhw*maxhh); -- cgit v1.2.3 From da24aa8d109a08b40b5547aacf3586026de78af2 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 5 Nov 2012 19:57:59 +0000 Subject: Merging r51897 through r51922 from trunk into soc-2011-tomato --- extern/carve/lib/intersect_face_division.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'extern') diff --git a/extern/carve/lib/intersect_face_division.cpp b/extern/carve/lib/intersect_face_division.cpp index 08550c021ad..c74b52dd557 100644 --- a/extern/carve/lib/intersect_face_division.cpp +++ b/extern/carve/lib/intersect_face_division.cpp @@ -1106,7 +1106,8 @@ namespace { } // copy up to the end of the path. - std::copy(base_loop.begin() + pos, base_loop.begin() + e1_1, std::back_inserter(out)); + if (pos < e1_1) + std::copy(base_loop.begin() + pos, base_loop.begin() + e1_1, std::back_inserter(out)); CARVE_ASSERT(base_loop[e1_1] == p1.back()); std::copy(p1.rbegin(), p1.rend() - 1, std::back_inserter(out)); -- cgit v1.2.3 From b1afaa8312cf2dcb601f0e91cef66efd62f0682a Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 10 Dec 2012 15:18:00 +0000 Subject: Merging r51923 through r52851 from trunk into soc-2011-tomato --- extern/CMakeLists.txt | 7 ++++--- extern/SConscript | 3 +++ extern/glew/src/glew.c | 4 ++-- extern/libmv/CMakeLists.txt | 3 +++ extern/libmv/libmv-capi.cpp | 7 +++++-- extern/libmv/libmv/simple_pipeline/resect.cc | 2 +- extern/xdnd/xdnd.c | 2 +- 7 files changed, 19 insertions(+), 9 deletions(-) (limited to 'extern') diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index 151df493062..2640c528c94 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -32,9 +32,10 @@ if(WITH_BULLET) add_subdirectory(bullet2) endif() -if(WITH_MOD_CLOTH_ELTOPO) - add_subdirectory(eltopo) -endif() +# now only available in a branch +#if(WITH_MOD_CLOTH_ELTOPO) +# add_subdirectory(eltopo) +#endif() if(WITH_BINRELOC) add_subdirectory(binreloc) diff --git a/extern/SConscript b/extern/SConscript index ce366deb38a..71998ee072c 100644 --- a/extern/SConscript +++ b/extern/SConscript @@ -8,8 +8,11 @@ SConscript(['colamd/SConscript']) if env['WITH_BF_GAMEENGINE']: SConscript(['recastnavigation/SConscript']) +# now only available in a branch +''' if env['WITH_BF_ELTOPO']: SConscript(['eltopo/SConscript']) +''' if env['WITH_BF_BULLET']: SConscript(['bullet2/src/SConscript']) diff --git a/extern/glew/src/glew.c b/extern/glew/src/glew.c index 5d886ce7807..833d3999268 100644 --- a/extern/glew/src/glew.c +++ b/extern/glew/src/glew.c @@ -93,7 +93,7 @@ void* dlGetProcAddress (const GLubyte* name) #include #include -#ifdef MAC_OS_X_VERSION_10_3 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3 #include @@ -142,7 +142,7 @@ void* NSGLGetProcAddress (const GLubyte *name) return NULL; #endif } -#endif /* MAC_OS_X_VERSION_10_3 */ +#endif /* MAC_OS_X_VERSION_MIN_REQUIRED */ #endif /* __APPLE__ */ /* diff --git a/extern/libmv/CMakeLists.txt b/extern/libmv/CMakeLists.txt index 38be34add75..ebc5953d956 100644 --- a/extern/libmv/CMakeLists.txt +++ b/extern/libmv/CMakeLists.txt @@ -102,6 +102,8 @@ set(SRC libmv/multiview/conditioning.h libmv/multiview/euclidean_resection.h libmv/multiview/fundamental.h + libmv/multiview/homography.h + libmv/multiview/homography_parameterization.h libmv/multiview/nviewtriangulation.h libmv/multiview/projection.h libmv/multiview/resection.h @@ -131,6 +133,7 @@ set(SRC libmv/tracking/pyramid_region_tracker.h libmv/tracking/region_tracker.h libmv/tracking/retrack_region_tracker.h + libmv/tracking/track_region.h libmv/tracking/trklt_region_tracker.h third_party/fast/fast.h diff --git a/extern/libmv/libmv-capi.cpp b/extern/libmv/libmv-capi.cpp index a15927f881d..8e483abd386 100644 --- a/extern/libmv/libmv-capi.cpp +++ b/extern/libmv/libmv-capi.cpp @@ -192,7 +192,7 @@ static void imageToFloatBuf(const libmv::FloatImage *image, int channels, float } #if defined(DUMP_FAILURE) || defined (DUMP_ALWAYS) -void savePNGImage(png_bytep *row_pointers, int width, int height, int depth, int color_type, char *file_name) +static void savePNGImage(png_bytep *row_pointers, int width, int height, int depth, int color_type, char *file_name) { png_infop info_ptr; png_structp png_ptr; @@ -437,6 +437,9 @@ int libmv_trackRegion(const struct libmv_trackRegionOptions *options, #endif saveImage("old_patch", old_patch, x1[4], y1[4]); saveImage("new_patch", new_patch, x2[4], y2[4]); + + if (options->image1_mask) + saveImage("mask", image1_mask, x2[4], y2[4]); } #endif @@ -897,7 +900,7 @@ void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmvIntrinsics intrinsics->SetFocalLength(focal_length, focal_length); if (intrinsics->principal_point_x() != principal_x || intrinsics->principal_point_y() != principal_y) - intrinsics->SetFocalLength(focal_length, focal_length); + intrinsics->SetPrincipalPoint(principal_x, principal_y); if (intrinsics->k1() != k1 || intrinsics->k2() != k2 || intrinsics->k3() != k3) intrinsics->SetRadialDistortion(k1, k2, k3); diff --git a/extern/libmv/libmv/simple_pipeline/resect.cc b/extern/libmv/libmv/simple_pipeline/resect.cc index 4c9ca6d8677..3929271e66f 100644 --- a/extern/libmv/libmv/simple_pipeline/resect.cc +++ b/extern/libmv/libmv/simple_pipeline/resect.cc @@ -57,7 +57,7 @@ struct EuclideanResectCostFunction { EuclideanResectCostFunction(const vector &markers, const EuclideanReconstruction &reconstruction, - const Mat3 initial_R) + const Mat3 &initial_R) : markers(markers), reconstruction(reconstruction), initial_R(initial_R) {} diff --git a/extern/xdnd/xdnd.c b/extern/xdnd/xdnd.c index 9bdee89c1ce..50d1fec4969 100644 --- a/extern/xdnd/xdnd.c +++ b/extern/xdnd/xdnd.c @@ -347,7 +347,7 @@ void xdnd_set_dnd_aware (DndClass * dnd, Window window, Atom * typelist) &nchildren_return); if (children_return) XFree (children_return); - if (r) + if (r && parent != root_return) xdnd_set_dnd_aware (dnd, parent, typelist); } -- cgit v1.2.3 From ec870eb2144391dbf0aed9d23b4e79c9dd982003 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 10 Dec 2012 16:38:13 +0000 Subject: code cleanup: camera tracking - Moved keyframes and refirement flags into reconstruction options structure - Moved distortion coefficients and other camera intrinsics into own structure - Cleaned up reconstruction functions in libmv c-api --- extern/libmv/libmv-capi.cpp | 126 ++++++++++++++++++++++++++++---------------- extern/libmv/libmv-capi.h | 38 ++++++++----- 2 files changed, 105 insertions(+), 59 deletions(-) (limited to 'extern') diff --git a/extern/libmv/libmv-capi.cpp b/extern/libmv/libmv-capi.cpp index 8e483abd386..ffe4b6ebf3d 100644 --- a/extern/libmv/libmv-capi.cpp +++ b/extern/libmv/libmv-capi.cpp @@ -552,40 +552,78 @@ static void libmv_solveRefineIntrinsics(libmv::Tracks *tracks, libmv::CameraIntr reconstruction, intrinsics); } -libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyframe1, int keyframe2, - int refine_intrinsics, double focal_length, double principal_x, double principal_y, - double k1, double k2, double k3, struct libmv_reconstructionOptions *options, - reconstruct_progress_update_cb progress_update_callback, void *callback_customdata) +static void cameraIntrinsicsFromOptions(libmv::CameraIntrinsics *camera_intrinsics, + libmv_cameraIntrinsicsOptions *camera_intrinsics_options) +{ + camera_intrinsics->SetFocalLength(camera_intrinsics_options->focal_length, + camera_intrinsics_options->focal_length); + + camera_intrinsics->SetPrincipalPoint(camera_intrinsics_options->principal_point_x, + camera_intrinsics_options->principal_point_y); + + camera_intrinsics->SetRadialDistortion(camera_intrinsics_options->k1, + camera_intrinsics_options->k2, + camera_intrinsics_options->k3); +} + +static libmv::Tracks getNormalizedTracks(libmv::Tracks *tracks, libmv::CameraIntrinsics *camera_intrinsics) +{ + libmv::vector markers = tracks->AllMarkers(); + + for (int i = 0; i < markers.size(); ++i) { + camera_intrinsics->InvertIntrinsics(markers[i].x, markers[i].y, + &(markers[i].x), &(markers[i].y)); + } + + return libmv::Tracks(markers); +} + +static void finishReconstruction(libmv::Tracks *tracks, libmv::CameraIntrinsics *camera_intrinsics, + libmv_Reconstruction *libmv_reconstruction, + reconstruct_progress_update_cb progress_update_callback, + void *callback_customdata) +{ + libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction; + + /* reprojection error calculation */ + progress_update_callback(callback_customdata, 1.0, "Finishing solution"); + libmv_reconstruction->tracks = *tracks; + libmv_reconstruction->error = libmv::EuclideanReprojectionError(*tracks, *reconstruction, *camera_intrinsics); +} + +libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *libmv_tracks, + libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, + libmv_reconstructionOptions *libmv_reconstruction_options, + reconstruct_progress_update_cb progress_update_callback, + void *callback_customdata) { - /* Invert the camera intrinsics. */ - libmv::vector markers = ((libmv::Tracks*)tracks)->AllMarkers(); libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction(); + + libmv::Tracks *tracks = ((libmv::Tracks *) libmv_tracks); libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction; - libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics; - libmv::ReconstructionOptions reconstruction_options; + libmv::CameraIntrinsics *camera_intrinsics = &libmv_reconstruction->intrinsics; ReconstructUpdateCallback update_callback = ReconstructUpdateCallback(progress_update_callback, callback_customdata); - intrinsics->SetFocalLength(focal_length, focal_length); - intrinsics->SetPrincipalPoint(principal_x, principal_y); - intrinsics->SetRadialDistortion(k1, k2, k3); + cameraIntrinsicsFromOptions(camera_intrinsics, libmv_camera_intrinsics_options); - reconstruction_options.success_threshold = options->success_threshold; - reconstruction_options.use_fallback_reconstruction = options->use_fallback_reconstruction; + /* Invert the camera intrinsics */ + libmv::Tracks normalized_tracks = getNormalizedTracks(tracks, camera_intrinsics); - for (int i = 0; i < markers.size(); ++i) { - intrinsics->InvertIntrinsics(markers[i].x, - markers[i].y, - &(markers[i].x), - &(markers[i].y)); - } + /* actual reconstruction */ + libmv::ReconstructionOptions reconstruction_options; + reconstruction_options.success_threshold = libmv_reconstruction_options->success_threshold; + reconstruction_options.use_fallback_reconstruction = libmv_reconstruction_options->use_fallback_reconstruction; - libmv::Tracks normalized_tracks(markers); + int keyframe1 = libmv_reconstruction_options->keyframe1, + keyframe2 = libmv_reconstruction_options->keyframe2; LG << "frames to init from: " << keyframe1 << " " << keyframe2; + libmv::vector keyframe_markers = normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2); + LG << "number of markers for init: " << keyframe_markers.size(); update_callback.invoke(0, "Initial reconstruction"); @@ -595,49 +633,45 @@ libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyfra libmv::EuclideanCompleteReconstruction(reconstruction_options, normalized_tracks, reconstruction, &update_callback); - if (refine_intrinsics) { - libmv_solveRefineIntrinsics((libmv::Tracks *)tracks, intrinsics, reconstruction, - refine_intrinsics, progress_update_callback, callback_customdata); + /* refinement */ + if (libmv_reconstruction_options->refine_intrinsics) { + libmv_solveRefineIntrinsics((libmv::Tracks *)tracks, camera_intrinsics, reconstruction, + libmv_reconstruction_options->refine_intrinsics, + progress_update_callback, callback_customdata); } - progress_update_callback(callback_customdata, 1.0, "Finishing solution"); - libmv_reconstruction->tracks = *(libmv::Tracks *)tracks; - libmv_reconstruction->error = libmv::EuclideanReprojectionError(*(libmv::Tracks *)tracks, *reconstruction, *intrinsics); + /* finish reconstruction */ + finishReconstruction(tracks, camera_intrinsics, libmv_reconstruction, + progress_update_callback, callback_customdata); return (libmv_Reconstruction *)libmv_reconstruction; } -struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *tracks, double focal_length, - double principal_x, double principal_y, double k1, double k2, double k3, - reconstruct_progress_update_cb progress_update_callback, void *callback_customdata) +struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *libmv_tracks, + libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, + reconstruct_progress_update_cb progress_update_callback, + void *callback_customdata) { - /* Invert the camera intrinsics. */ - libmv::vector markers = ((libmv::Tracks*)tracks)->AllMarkers(); libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction(); + + libmv::Tracks *tracks = ((libmv::Tracks *) libmv_tracks); libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction; - libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics; + libmv::CameraIntrinsics *camera_intrinsics = &libmv_reconstruction->intrinsics; ReconstructUpdateCallback update_callback = ReconstructUpdateCallback(progress_update_callback, callback_customdata); - intrinsics->SetFocalLength(focal_length, focal_length); - intrinsics->SetPrincipalPoint(principal_x, principal_y); - intrinsics->SetRadialDistortion(k1, k2, k3); - - for (int i = 0; i < markers.size(); ++i) { - intrinsics->InvertIntrinsics(markers[i].x, - markers[i].y, - &(markers[i].x), - &(markers[i].y)); - } + cameraIntrinsicsFromOptions(camera_intrinsics, libmv_camera_intrinsics_options); - libmv::Tracks normalized_tracks(markers); + /* Invert the camera intrinsics */ + libmv::Tracks normalized_tracks = getNormalizedTracks(tracks, camera_intrinsics); + /* actual reconstruction */ libmv::ModalSolver(normalized_tracks, reconstruction, &update_callback); - progress_update_callback(callback_customdata, 1.0, "Finishing solution"); - libmv_reconstruction->tracks = *(libmv::Tracks *)tracks; - libmv_reconstruction->error = libmv::EuclideanReprojectionError(*(libmv::Tracks *)tracks, *reconstruction, *intrinsics); + /* finish reconstruction */ + finishReconstruction(tracks, camera_intrinsics, libmv_reconstruction, + progress_update_callback, callback_customdata); return (libmv_Reconstruction *)libmv_reconstruction; } diff --git a/extern/libmv/libmv-capi.h b/extern/libmv/libmv-capi.h index e5885e7addf..317f5520aa9 100644 --- a/extern/libmv/libmv-capi.h +++ b/extern/libmv/libmv-capi.h @@ -86,28 +86,40 @@ void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track, void libmv_tracksDestroy(struct libmv_Tracks *libmv_tracks); /* Reconstruction solver */ -#define LIBMV_REFINE_FOCAL_LENGTH (1<<0) -#define LIBMV_REFINE_PRINCIPAL_POINT (1<<1) -#define LIBMV_REFINE_RADIAL_DISTORTION_K1 (1<<2) -#define LIBMV_REFINE_RADIAL_DISTORTION_K2 (1<<4) -/* TODO: make keyframes/distortion model a part of options? */ -struct libmv_reconstructionOptions { +#define LIBMV_REFINE_FOCAL_LENGTH (1 << 0) +#define LIBMV_REFINE_PRINCIPAL_POINT (1 << 1) +#define LIBMV_REFINE_RADIAL_DISTORTION_K1 (1 << 2) +#define LIBMV_REFINE_RADIAL_DISTORTION_K2 (1 << 4) + +typedef struct libmv_cameraIntrinsicsOptions { + double focal_length; + double principal_point_x, principal_point_y; + double k1, k2, k3; + double p1, p2; +} libmv_cameraIntrinsicsOptions; + +typedef struct libmv_reconstructionOptions { + int keyframe1, keyframe2; + int refine_intrinsics; + double success_threshold; int use_fallback_reconstruction; -}; +} libmv_reconstructionOptions; typedef void (*reconstruct_progress_update_cb) (void *customdata, double progress, const char *message); int libmv_refineParametersAreValid(int parameters); -struct libmv_Reconstruction *libmv_solveReconstruction(struct libmv_Tracks *tracks, int keyframe1, int keyframe2, - int refine_intrinsics, double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, - struct libmv_reconstructionOptions *options, reconstruct_progress_update_cb progress_update_callback, +struct libmv_Reconstruction *libmv_solveReconstruction(struct libmv_Tracks *libmv_tracks, + libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, + libmv_reconstructionOptions *libmv_reconstruction_options, + reconstruct_progress_update_cb progress_update_callback, + void *callback_customdata); +struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *libmv_tracks, + libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, + reconstruct_progress_update_cb progress_update_callback, void *callback_customdata); -struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *tracks, double focal_length, - double principal_x, double principal_y, double k1, double k2, double k3, - reconstruct_progress_update_cb progress_update_callback, void *callback_customdata); int libmv_reporojectionPointForTrack(struct libmv_Reconstruction *libmv_reconstruction, int track, double pos[3]); double libmv_reporojectionErrorForTrack(struct libmv_Reconstruction *libmv_reconstruction, int track); double libmv_reporojectionErrorForImage(struct libmv_Reconstruction *libmv_reconstruction, int image); -- cgit v1.2.3 From 5137b5a146e9ed701f2b41bcd7cb08a6251e9601 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 10 Dec 2012 16:38:28 +0000 Subject: Camera tracking: libmv distortion API now also uses camera intrinsics structure instead of passing all the parameters to every function. Makes it much easier to tweak distortion model. --- extern/libmv/libmv-capi.cpp | 162 ++++++++++++++++++++++++-------------------- extern/libmv/libmv-capi.h | 34 +++++----- 2 files changed, 105 insertions(+), 91 deletions(-) (limited to 'extern') diff --git a/extern/libmv/libmv-capi.cpp b/extern/libmv/libmv-capi.cpp index ffe4b6ebf3d..41235523179 100644 --- a/extern/libmv/libmv-capi.cpp +++ b/extern/libmv/libmv-capi.cpp @@ -564,6 +564,9 @@ static void cameraIntrinsicsFromOptions(libmv::CameraIntrinsics *camera_intrinsi camera_intrinsics->SetRadialDistortion(camera_intrinsics_options->k1, camera_intrinsics_options->k2, camera_intrinsics_options->k3); + + camera_intrinsics->SetImageSize(camera_intrinsics_options->image_width, + camera_intrinsics_options->image_height); } static libmv::Tracks getNormalizedTracks(libmv::Tracks *tracks, libmv::CameraIntrinsics *camera_intrinsics) @@ -897,17 +900,13 @@ struct libmv_CameraIntrinsics *libmv_ReconstructionExtractIntrinsics(struct libm return (struct libmv_CameraIntrinsics *)&libmv_Reconstruction->intrinsics; } -struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(double focal_length, double principal_x, double principal_y, - double k1, double k2, double k3, int width, int height) +struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options) { - libmv::CameraIntrinsics *intrinsics= new libmv::CameraIntrinsics(); + libmv::CameraIntrinsics *camera_intrinsics = new libmv::CameraIntrinsics(); - intrinsics->SetFocalLength(focal_length, focal_length); - intrinsics->SetPrincipalPoint(principal_x, principal_y); - intrinsics->SetRadialDistortion(k1, k2, k3); - intrinsics->SetImageSize(width, height); + cameraIntrinsicsFromOptions(camera_intrinsics, libmv_camera_intrinsics_options); - return (struct libmv_CameraIntrinsics *) intrinsics; + return (struct libmv_CameraIntrinsics *) camera_intrinsics; } struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsCopy(struct libmv_CameraIntrinsics *libmvIntrinsics) @@ -925,40 +924,63 @@ void libmv_CameraIntrinsicsDestroy(struct libmv_CameraIntrinsics *libmvIntrinsic delete intrinsics; } -void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmvIntrinsics, double focal_length, - double principal_x, double principal_y, double k1, double k2, double k3, int width, int height) +void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmv_intrinsics, + libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options) { - libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics; + libmv::CameraIntrinsics *camera_intrinsics = (libmv::CameraIntrinsics *) libmv_intrinsics; - if (intrinsics->focal_length() != focal_length) - intrinsics->SetFocalLength(focal_length, focal_length); + double focal_length = libmv_camera_intrinsics_options->focal_length; + double principal_x = libmv_camera_intrinsics_options->principal_point_x; + double principal_y = libmv_camera_intrinsics_options->principal_point_y; + double k1 = libmv_camera_intrinsics_options->k1; + double k2 = libmv_camera_intrinsics_options->k2; + double k3 = libmv_camera_intrinsics_options->k3; + int image_width = libmv_camera_intrinsics_options->image_width; + int image_height = libmv_camera_intrinsics_options->image_height; - if (intrinsics->principal_point_x() != principal_x || intrinsics->principal_point_y() != principal_y) - intrinsics->SetPrincipalPoint(principal_x, principal_y); + /* try avoid unnecessary updates so pre-computed distortion grids are not freed */ - if (intrinsics->k1() != k1 || intrinsics->k2() != k2 || intrinsics->k3() != k3) - intrinsics->SetRadialDistortion(k1, k2, k3); + if (camera_intrinsics->focal_length() != focal_length) + camera_intrinsics->SetFocalLength(focal_length, focal_length); - if (intrinsics->image_width() != width || intrinsics->image_height() != height) - intrinsics->SetImageSize(width, height); + if (camera_intrinsics->principal_point_x() != principal_x || + camera_intrinsics->principal_point_y() != principal_y) + { + camera_intrinsics->SetPrincipalPoint(principal_x, principal_y); + } + + if (camera_intrinsics->k1() != k1 || + camera_intrinsics->k2() != k2 || + camera_intrinsics->k3() != k3) + { + camera_intrinsics->SetRadialDistortion(k1, k2, k3); + } + + if (camera_intrinsics->image_width() != image_width || + camera_intrinsics->image_height() != image_height) + { + camera_intrinsics->SetImageSize(image_width, image_height); + } } -void libmv_CameraIntrinsicsExtract(struct libmv_CameraIntrinsics *libmvIntrinsics, double *focal_length, - double *principal_x, double *principal_y, double *k1, double *k2, double *k3, int *width, int *height) { - libmv::CameraIntrinsics *intrinsics= (libmv::CameraIntrinsics *) libmvIntrinsics; - *focal_length = intrinsics->focal_length(); - *principal_x = intrinsics->principal_point_x(); - *principal_y = intrinsics->principal_point_y(); - *k1 = intrinsics->k1(); - *k2 = intrinsics->k2(); +void libmv_CameraIntrinsicsExtract(struct libmv_CameraIntrinsics *libmv_intrinsics, double *focal_length, + double *principal_x, double *principal_y, double *k1, double *k2, double *k3, int *width, int *height) +{ + libmv::CameraIntrinsics *camera_intrinsics = (libmv::CameraIntrinsics *) libmv_intrinsics; + + *focal_length = camera_intrinsics->focal_length(); + *principal_x = camera_intrinsics->principal_point_x(); + *principal_y = camera_intrinsics->principal_point_y(); + *k1 = camera_intrinsics->k1(); + *k2 = camera_intrinsics->k2(); } -void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics, +void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmv_intrinsics, unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels) { - libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics; + libmv::CameraIntrinsics *camera_intrinsics = (libmv::CameraIntrinsics *) libmv_intrinsics; - intrinsics->Undistort(src, dst, width, height, overscan, channels); + camera_intrinsics->Undistort(src, dst, width, height, overscan, channels); } void libmv_CameraIntrinsicsUndistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics, @@ -986,85 +1008,77 @@ void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmvIntr /* ************ distortion ************ */ -void libmv_undistortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, - unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels) +void libmv_undistortByte(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, + unsigned char *src, unsigned char *dst, int width, int height, + float overscan, int channels) { - libmv::CameraIntrinsics intrinsics; + libmv::CameraIntrinsics camera_intrinsics; - intrinsics.SetFocalLength(focal_length, focal_length); - intrinsics.SetPrincipalPoint(principal_x, principal_y); - intrinsics.SetRadialDistortion(k1, k2, k3); + cameraIntrinsicsFromOptions(&camera_intrinsics, libmv_camera_intrinsics_options); - intrinsics.Undistort(src, dst, width, height, overscan, channels); + camera_intrinsics.Undistort(src, dst, width, height, overscan, channels); } -void libmv_undistortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, - float *src, float *dst, int width, int height, float overscan, int channels) +void libmv_undistortFloat(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, + float *src, float *dst, int width, int height, + float overscan, int channels) { - libmv::CameraIntrinsics intrinsics; + libmv::CameraIntrinsics camera_intrinsics; - intrinsics.SetFocalLength(focal_length, focal_length); - intrinsics.SetPrincipalPoint(principal_x, principal_y); - intrinsics.SetRadialDistortion(k1, k2, k3); + cameraIntrinsicsFromOptions(&camera_intrinsics, libmv_camera_intrinsics_options); - intrinsics.Undistort(src, dst, width, height, overscan, channels); + camera_intrinsics.Undistort(src, dst, width, height, overscan, channels); } -void libmv_distortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, - unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels) +void libmv_distortByte(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, + unsigned char *src, unsigned char *dst, int width, int height, + float overscan, int channels) { - libmv::CameraIntrinsics intrinsics; + libmv::CameraIntrinsics camera_intrinsics; - intrinsics.SetFocalLength(focal_length, focal_length); - intrinsics.SetPrincipalPoint(principal_x, principal_y); - intrinsics.SetRadialDistortion(k1, k2, k3); + cameraIntrinsicsFromOptions(&camera_intrinsics, libmv_camera_intrinsics_options); - intrinsics.Distort(src, dst, width, height, overscan, channels); + camera_intrinsics.Distort(src, dst, width, height, overscan, channels); } -void libmv_distortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, - float *src, float *dst, int width, int height, float overscan, int channels) +void libmv_distortFloat(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, + float *src, float *dst, int width, int height, + float overscan, int channels) { - libmv::CameraIntrinsics intrinsics; + libmv::CameraIntrinsics camera_intrinsics; - intrinsics.SetFocalLength(focal_length, focal_length); - intrinsics.SetPrincipalPoint(principal_x, principal_y); - intrinsics.SetRadialDistortion(k1, k2, k3); + cameraIntrinsicsFromOptions(&camera_intrinsics, libmv_camera_intrinsics_options); - intrinsics.Distort(src, dst, width, height, overscan, channels); + camera_intrinsics.Distort(src, dst, width, height, overscan, channels); } /* ************ utils ************ */ -void libmv_applyCameraIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, - double x, double y, double *x1, double *y1) +void libmv_applyCameraIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, + double x, double y, double *x1, double *y1) { - libmv::CameraIntrinsics intrinsics; + libmv::CameraIntrinsics camera_intrinsics; - intrinsics.SetFocalLength(focal_length, focal_length); - intrinsics.SetPrincipalPoint(principal_x, principal_y); - intrinsics.SetRadialDistortion(k1, k2, k3); + cameraIntrinsicsFromOptions(&camera_intrinsics, libmv_camera_intrinsics_options); - if(focal_length) { + if (libmv_camera_intrinsics_options->focal_length) { /* do a lens undistortion if focal length is non-zero only */ - intrinsics.ApplyIntrinsics(x, y, x1, y1); + camera_intrinsics.ApplyIntrinsics(x, y, x1, y1); } } -void libmv_InvertIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, - double x, double y, double *x1, double *y1) +void libmv_InvertIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, + double x, double y, double *x1, double *y1) { - libmv::CameraIntrinsics intrinsics; + libmv::CameraIntrinsics camera_intrinsics; - intrinsics.SetFocalLength(focal_length, focal_length); - intrinsics.SetPrincipalPoint(principal_x, principal_y); - intrinsics.SetRadialDistortion(k1, k2, k3); + cameraIntrinsicsFromOptions(&camera_intrinsics, libmv_camera_intrinsics_options); - if(focal_length) { + if (libmv_camera_intrinsics_options->focal_length) { /* do a lens distortion if focal length is non-zero only */ - intrinsics.InvertIntrinsics(x, y, x1, y1); + camera_intrinsics.InvertIntrinsics(x, y, x1, y1); } } diff --git a/extern/libmv/libmv-capi.h b/extern/libmv/libmv-capi.h index 317f5520aa9..9ffa3e1a110 100644 --- a/extern/libmv/libmv-capi.h +++ b/extern/libmv/libmv-capi.h @@ -97,6 +97,7 @@ typedef struct libmv_cameraIntrinsicsOptions { double principal_point_x, principal_point_y; double k1, k2, k3; double p1, p2; + int image_width, image_height; } libmv_cameraIntrinsicsOptions; typedef struct libmv_reconstructionOptions { @@ -139,46 +140,45 @@ void libmv_destroyFeatures(struct libmv_Features *libmv_features); /* camera intrinsics */ struct libmv_CameraIntrinsics *libmv_ReconstructionExtractIntrinsics(struct libmv_Reconstruction *libmv_Reconstruction); -struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(double focal_length, double principal_x, double principal_y, - double k1, double k2, double k3, int width, int height); +struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options); -struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsCopy(struct libmv_CameraIntrinsics *libmvIntrinsics); +struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsCopy(struct libmv_CameraIntrinsics *libmv_intrinsics); -void libmv_CameraIntrinsicsDestroy(struct libmv_CameraIntrinsics *libmvIntrinsics); +void libmv_CameraIntrinsicsDestroy(struct libmv_CameraIntrinsics *libmv_intrinsics); -void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmvIntrinsics, double focal_length, - double principal_x, double principal_y, double k1, double k2, double k3, int width, int height); +void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmv_intrinsics, + libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options); -void libmv_CameraIntrinsicsExtract(struct libmv_CameraIntrinsics *libmvIntrinsics, double *focal_length, +void libmv_CameraIntrinsicsExtract(struct libmv_CameraIntrinsics *libmv_intrinsics, double *focal_length, double *principal_x, double *principal_y, double *k1, double *k2, double *k3, int *width, int *height); -void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics, +void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmv_intrinsics, unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels); -void libmv_CameraIntrinsicsUndistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics, +void libmv_CameraIntrinsicsUndistortFloat(struct libmv_CameraIntrinsics *libmv_intrinsics, float *src, float *dst, int width, int height, float overscan, int channels); -void libmv_CameraIntrinsicsDistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics, +void libmv_CameraIntrinsicsDistortByte(struct libmv_CameraIntrinsics *libmv_intrinsics, unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels); -void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics, +void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmv_intrinsics, float *src, float *dst, int width, int height, float overscan, int channels); /* dsitortion */ -void libmv_undistortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, +void libmv_undistortByte(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels); -void libmv_undistortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, +void libmv_undistortFloat(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, float *src, float *dst, int width, int height, float overscan, int channels); -void libmv_distortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, +void libmv_distortByte(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels); -void libmv_distortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, +void libmv_distortFloat(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, float *src, float *dst, int width, int height, float overscan, int channels); /* utils */ -void libmv_applyCameraIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, +void libmv_applyCameraIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, double x, double y, double *x1, double *y1); -void libmv_InvertIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, +void libmv_InvertIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, double x, double y, double *x1, double *y1); /* point clouds */ -- cgit v1.2.3 From da2dc58773919ce7d571c00441a590d48c8fd849 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 10 Dec 2012 16:38:39 +0000 Subject: code cleanup: remove unused and unsupported functions from libmv-capi --- extern/libmv/libmv-capi.cpp | 129 +------------------------------------------- extern/libmv/libmv-capi.h | 19 ------- 2 files changed, 1 insertion(+), 147 deletions(-) (limited to 'extern') diff --git a/extern/libmv/libmv-capi.cpp b/extern/libmv/libmv-capi.cpp index 41235523179..bc6b0e99834 100644 --- a/extern/libmv/libmv-capi.cpp +++ b/extern/libmv/libmv-capi.cpp @@ -117,51 +117,7 @@ void libmv_setLoggingVerbosity(int verbosity) V3D::optimizerVerbosenessLevel = verbosity; } -/* ************ RegionTracker ************ */ - -libmv_RegionTracker *libmv_pyramidRegionTrackerNew(int max_iterations, int pyramid_level, int half_window_size, double minimum_correlation) -{ - libmv::EsmRegionTracker *esm_region_tracker = new libmv::EsmRegionTracker; - esm_region_tracker->half_window_size = half_window_size; - esm_region_tracker->max_iterations = max_iterations; - esm_region_tracker->min_determinant = 1e-4; - esm_region_tracker->minimum_correlation = minimum_correlation; - - libmv::PyramidRegionTracker *pyramid_region_tracker = - new libmv::PyramidRegionTracker(esm_region_tracker, pyramid_level); - - return (libmv_RegionTracker *)pyramid_region_tracker; -} - -libmv_RegionTracker *libmv_hybridRegionTrackerNew(int max_iterations, int half_window_size, double minimum_correlation) -{ - libmv::EsmRegionTracker *esm_region_tracker = new libmv::EsmRegionTracker; - esm_region_tracker->half_window_size = half_window_size; - esm_region_tracker->max_iterations = max_iterations; - esm_region_tracker->min_determinant = 1e-4; - esm_region_tracker->minimum_correlation = minimum_correlation; - - libmv::BruteRegionTracker *brute_region_tracker = new libmv::BruteRegionTracker; - brute_region_tracker->half_window_size = half_window_size; - - /* do not use correlation check for brute checker itself, - * this check will happen in esm tracker */ - brute_region_tracker->minimum_correlation = 0.0; - - libmv::HybridRegionTracker *hybrid_region_tracker = - new libmv::HybridRegionTracker(brute_region_tracker, esm_region_tracker); - - return (libmv_RegionTracker *)hybrid_region_tracker; -} - -libmv_RegionTracker *libmv_bruteRegionTrackerNew(int half_window_size, double minimum_correlation) -{ - libmv::BruteRegionTracker *brute_region_tracker = new libmv::BruteRegionTracker; - brute_region_tracker->half_window_size = half_window_size; - brute_region_tracker->minimum_correlation = minimum_correlation; - - return (libmv_RegionTracker *)brute_region_tracker; -} +/* ************ Utility ************ */ static void floatBufToImage(const float *buf, int width, int height, int channels, libmv::FloatImage *image) { @@ -316,43 +272,6 @@ static void saveBytesImage(const char *prefix, unsigned char *data, int width, i } #endif -int libmv_regionTrackerTrack(libmv_RegionTracker *libmv_tracker, const float *ima1, const float *ima2, - int width, int height, double x1, double y1, double *x2, double *y2) -{ - libmv::RegionTracker *region_tracker = (libmv::RegionTracker *)libmv_tracker; - libmv::FloatImage old_patch, new_patch; - - floatBufToImage(ima1, width, height, 1, &old_patch); - floatBufToImage(ima2, width, height, 1, &new_patch); - -#if !defined(DUMP_FAILURE) && !defined(DUMP_ALWAYS) - return region_tracker->Track(old_patch, new_patch, x1, y1, x2, y2); -#else - { - /* double sx2 = *x2, sy2 = *y2; */ - int result = region_tracker->Track(old_patch, new_patch, x1, y1, x2, y2); - -#if defined(DUMP_ALWAYS) - { -#else - if (!result) { -#endif - saveImage("old_patch", old_patch, x1, y1); - saveImage("new_patch", new_patch, *x2, *y2); - } - - return result; - } -#endif -} - -void libmv_regionTrackerDestroy(libmv_RegionTracker *libmv_tracker) -{ - libmv::RegionTracker *region_tracker= (libmv::RegionTracker *)libmv_tracker; - - delete region_tracker; -} - /* ************ Planar tracker ************ */ /* TrackRegion (new planar tracker) */ @@ -1006,52 +925,6 @@ void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmvIntr intrinsics->Distort(src, dst, width, height, overscan, channels); } -/* ************ distortion ************ */ - -void libmv_undistortByte(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, - unsigned char *src, unsigned char *dst, int width, int height, - float overscan, int channels) -{ - libmv::CameraIntrinsics camera_intrinsics; - - cameraIntrinsicsFromOptions(&camera_intrinsics, libmv_camera_intrinsics_options); - - camera_intrinsics.Undistort(src, dst, width, height, overscan, channels); -} - -void libmv_undistortFloat(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, - float *src, float *dst, int width, int height, - float overscan, int channels) -{ - libmv::CameraIntrinsics camera_intrinsics; - - cameraIntrinsicsFromOptions(&camera_intrinsics, libmv_camera_intrinsics_options); - - camera_intrinsics.Undistort(src, dst, width, height, overscan, channels); -} - -void libmv_distortByte(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, - unsigned char *src, unsigned char *dst, int width, int height, - float overscan, int channels) -{ - libmv::CameraIntrinsics camera_intrinsics; - - cameraIntrinsicsFromOptions(&camera_intrinsics, libmv_camera_intrinsics_options); - - camera_intrinsics.Distort(src, dst, width, height, overscan, channels); -} - -void libmv_distortFloat(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, - float *src, float *dst, int width, int height, - float overscan, int channels) -{ - libmv::CameraIntrinsics camera_intrinsics; - - cameraIntrinsicsFromOptions(&camera_intrinsics, libmv_camera_intrinsics_options); - - camera_intrinsics.Distort(src, dst, width, height, overscan, channels); -} - /* ************ utils ************ */ void libmv_applyCameraIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, diff --git a/extern/libmv/libmv-capi.h b/extern/libmv/libmv-capi.h index 9ffa3e1a110..ba737160047 100644 --- a/extern/libmv/libmv-capi.h +++ b/extern/libmv/libmv-capi.h @@ -42,14 +42,6 @@ void libmv_initLogging(const char *argv0); void libmv_startDebugLogging(void); void libmv_setLoggingVerbosity(int verbosity); -/* RegionTracker */ -struct libmv_RegionTracker *libmv_pyramidRegionTrackerNew(int max_iterations, int pyramid_level, int half_window_size, double minimum_correlation); -struct libmv_RegionTracker *libmv_hybridRegionTrackerNew(int max_iterations, int half_window_size, double minimum_correlation); -struct libmv_RegionTracker *libmv_bruteRegionTrackerNew(int half_window_size, double minimum_correlation); -int libmv_regionTrackerTrack(struct libmv_RegionTracker *libmv_tracker, const float *ima1, const float *ima2, - int width, int height, double x1, double y1, double *x2, double *y2); -void libmv_regionTrackerDestroy(struct libmv_RegionTracker *libmv_tracker); - /* TrackRegion (new planar tracker) */ struct libmv_trackRegionOptions { int motion_model; @@ -164,17 +156,6 @@ void libmv_CameraIntrinsicsDistortByte(struct libmv_CameraIntrinsics *libmv_intr void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmv_intrinsics, float *src, float *dst, int width, int height, float overscan, int channels); -/* dsitortion */ -void libmv_undistortByte(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, - unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels); -void libmv_undistortFloat(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, - float *src, float *dst, int width, int height, float overscan, int channels); - -void libmv_distortByte(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, - unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels); -void libmv_distortFloat(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, - float *src, float *dst, int width, int height, float overscan, int channels); - /* utils */ void libmv_applyCameraIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, double x, double y, double *x1, double *y1); -- cgit v1.2.3 From 23d603bdbf5b7a8e5237c043f234f103d02ed57c Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 25 Feb 2013 08:16:28 +0000 Subject: Update bundled version of minilzo This updates minilzo from version 2.03 to version 2.06 which is like 3 years newer. The main reason of this update is that older minilzo had some strange valgrind warnings. Likely they're harmless, but it was still annoying to troubleshot bakes with valgrind. --- extern/lzo/minilzo/COPYING | 29 +- extern/lzo/minilzo/README.LZO | 27 +- extern/lzo/minilzo/lzoconf.h | 79 ++- extern/lzo/minilzo/lzodefs.h | 179 +++--- extern/lzo/minilzo/minilzo.c | 1195 ++++++++++++++++++++++++++++------------- extern/lzo/minilzo/minilzo.h | 8 +- 6 files changed, 1030 insertions(+), 487 deletions(-) (limited to 'extern') diff --git a/extern/lzo/minilzo/COPYING b/extern/lzo/minilzo/COPYING index 5ee49f42e91..d159169d105 100644 --- a/extern/lzo/minilzo/COPYING +++ b/extern/lzo/minilzo/COPYING @@ -1,8 +1,8 @@ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to +the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not @@ -55,7 +55,7 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION @@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions: License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -225,7 +225,7 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -278,7 +278,7 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS - + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest @@ -291,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - Copyright (C) 19yy + Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -303,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. @@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names: This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General +library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. diff --git a/extern/lzo/minilzo/README.LZO b/extern/lzo/minilzo/README.LZO index 3700f28e310..058eace70a0 100644 --- a/extern/lzo/minilzo/README.LZO +++ b/extern/lzo/minilzo/README.LZO @@ -6,8 +6,8 @@ Author : Markus Franz Xaver Johannes Oberhumer http://www.oberhumer.com/opensource/lzo/ - Version : 2.03 - Date : 30 Apr 2008 + Version : 2.06 + Date : 12 Aug 2011 I've created miniLZO for projects where it is inconvenient to include (or require) the full LZO source code just because you @@ -24,10 +24,10 @@ To use miniLZO just copy these files into your source directory, add minilzo.c to your Makefile and #include minilzo.h from your program. - Note: you also must distribute this file (`README.LZO') with your project. + Note: you also must distribute this file ('README.LZO') with your project. - minilzo.o compiles to about 6 kB (using gcc or Visual C on a i386), and - the sources are about 30 kB when packed with zip - so there's no more + minilzo.o compiles to about 6 KiB (using gcc or Visual C on an i386), and + the sources are about 30 KiB when packed with zip - so there's no more excuse that your application doesn't support data compression :-) For more information, documentation, example programs and other support @@ -49,15 +49,15 @@ out-of-the-box on most machines. If you are running on a very unusual architecture and lzo_init() fails then - you should first recompile with `-DLZO_DEBUG' to see what causes the failure. - The most probable case is something like `sizeof(char *) != sizeof(long)'. + you should first recompile with '-DLZO_DEBUG' to see what causes the failure. + The most probable case is something like 'sizeof(void *) != sizeof(size_t)'. After identifying the problem you can compile by adding some defines - like `-DSIZEOF_CHAR_P=8' to your Makefile. + like '-DSIZEOF_VOID_P=8' to your Makefile. The best solution is (of course) using Autoconf - if your project uses - Autoconf anyway just add `-DMINILZO_HAVE_CONFIG_H' to your compiler + Autoconf anyway just add '-DMINILZO_HAVE_CONFIG_H' to your compiler flags when compiling minilzo.c. See the LZO distribution for an example - how to set up configure.in. + how to set up configure.ac. Appendix B: list of public functions available in miniLZO @@ -87,7 +87,7 @@ lzo_memset() - Appendix C: suggested macros for `configure.in' when using Autoconf + Appendix C: suggested macros for 'configure.ac' when using Autoconf ------------------------------------------------------------------- Checks for typedefs and structures AC_CHECK_TYPE(ptrdiff_t,long) @@ -110,8 +110,9 @@ Appendix D: Copyright --------------------- - LZO and miniLZO are Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005, 2006, 2007, 2008 Markus Franz Xaver Johannes Oberhumer + LZO and miniLZO are Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + Markus Franz Xaver Oberhumer . LZO and miniLZO are distributed under the terms of the GNU General Public License (GPL). See the file COPYING. diff --git a/extern/lzo/minilzo/lzoconf.h b/extern/lzo/minilzo/lzoconf.h index cc437f1ebfe..23c6ca93fcc 100644 --- a/extern/lzo/minilzo/lzoconf.h +++ b/extern/lzo/minilzo/lzoconf.h @@ -1,7 +1,10 @@ -/* lzoconf.h -- configuration for the LZO real-time data compression library +/* lzoconf.h -- configuration of the LZO data compression library This file is part of the LZO real-time data compression library. + Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer @@ -39,11 +42,11 @@ #ifndef __LZOCONF_H_INCLUDED -#define __LZOCONF_H_INCLUDED +#define __LZOCONF_H_INCLUDED 1 -#define LZO_VERSION 0x2030 -#define LZO_VERSION_STRING "2.03" -#define LZO_VERSION_DATE "Apr 30 2008" +#define LZO_VERSION 0x2060 +#define LZO_VERSION_STRING "2.06" +#define LZO_VERSION_DATE "Aug 12 2011" /* internal Autoconf configuration file - only used when building LZO */ #if defined(LZO_HAVE_CONFIG_H) @@ -157,6 +160,27 @@ extern "C" { # endif #endif +/* Integral types with exactly 64 bits. */ +#if !defined(LZO_UINT64_MAX) +# if (LZO_UINT_MAX >= LZO_0xffffffffL) +# if ((((LZO_UINT_MAX) >> 31) >> 31) == 3) +# define lzo_uint64 lzo_uint +# define lzo_int64 lzo_int +# define LZO_UINT64_MAX LZO_UINT_MAX +# define LZO_INT64_MAX LZO_INT_MAX +# define LZO_INT64_MIN LZO_INT_MIN +# endif +# elif (ULONG_MAX >= LZO_0xffffffffL) +# if ((((ULONG_MAX) >> 31) >> 31) == 3) + typedef unsigned long lzo_uint64; + typedef long lzo_int64; +# define LZO_UINT64_MAX ULONG_MAX +# define LZO_INT64_MAX LONG_MAX +# define LZO_INT64_MIN LONG_MIN +# endif +# endif +#endif + /* The larger type of lzo_uint and lzo_uint32. */ #if (LZO_UINT_MAX >= LZO_UINT32_MAX) # define lzo_xint lzo_uint @@ -167,12 +191,12 @@ extern "C" { /* Memory model that allows to access memory at offsets of lzo_uint. */ #if !defined(__LZO_MMODEL) # if (LZO_UINT_MAX <= UINT_MAX) -# define __LZO_MMODEL +# define __LZO_MMODEL /*empty*/ # elif defined(LZO_HAVE_MM_HUGE_PTR) # define __LZO_MMODEL_HUGE 1 # define __LZO_MMODEL __huge # else -# define __LZO_MMODEL +# define __LZO_MMODEL /*empty*/ # endif #endif @@ -184,12 +208,16 @@ extern "C" { #define lzo_ushortp unsigned short __LZO_MMODEL * #define lzo_uint32p lzo_uint32 __LZO_MMODEL * #define lzo_int32p lzo_int32 __LZO_MMODEL * +#if defined(LZO_UINT64_MAX) +#define lzo_uint64p lzo_uint64 __LZO_MMODEL * +#define lzo_int64p lzo_int64 __LZO_MMODEL * +#endif #define lzo_uintp lzo_uint __LZO_MMODEL * #define lzo_intp lzo_int __LZO_MMODEL * #define lzo_xintp lzo_xint __LZO_MMODEL * #define lzo_voidpp lzo_voidp __LZO_MMODEL * #define lzo_bytepp lzo_bytep __LZO_MMODEL * -/* deprecated - use `lzo_bytep' instead of `lzo_byte *' */ +/* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */ #define lzo_byte unsigned char __LZO_MMODEL typedef int lzo_bool; @@ -215,10 +243,10 @@ typedef int lzo_bool; /* DLL export information */ #if !defined(__LZO_EXPORT1) -# define __LZO_EXPORT1 +# define __LZO_EXPORT1 /*empty*/ #endif #if !defined(__LZO_EXPORT2) -# define __LZO_EXPORT2 +# define __LZO_EXPORT2 /*empty*/ #endif /* __cdecl calling convention for public C and assembly functions */ @@ -306,7 +334,7 @@ struct lzo_callback_t */ #define LZO_E_OK 0 #define LZO_E_ERROR (-1) -#define LZO_E_OUT_OF_MEMORY (-2) /* [not used right now] */ +#define LZO_E_OUT_OF_MEMORY (-2) /* [lzo_alloc_func_t failure] */ #define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */ #define LZO_E_INPUT_OVERRUN (-4) #define LZO_E_OUTPUT_OVERRUN (-5) @@ -314,6 +342,7 @@ struct lzo_callback_t #define LZO_E_EOF_NOT_FOUND (-7) #define LZO_E_INPUT_NOT_CONSUMED (-8) #define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */ +#define LZO_E_INVALID_ARGUMENT (-10) #ifndef lzo_sizeof_dict_t @@ -341,32 +370,32 @@ LZO_EXTERN(const lzo_charp) _lzo_version_date(void); /* string functions */ LZO_EXTERN(int) -lzo_memcmp(const lzo_voidp _s1, const lzo_voidp _s2, lzo_uint _len); + lzo_memcmp(const lzo_voidp a, const lzo_voidp b, lzo_uint len); LZO_EXTERN(lzo_voidp) -lzo_memcpy(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len); + lzo_memcpy(lzo_voidp dst, const lzo_voidp src, lzo_uint len); LZO_EXTERN(lzo_voidp) -lzo_memmove(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len); + lzo_memmove(lzo_voidp dst, const lzo_voidp src, lzo_uint len); LZO_EXTERN(lzo_voidp) -lzo_memset(lzo_voidp _s, int _c, lzo_uint _len); + lzo_memset(lzo_voidp buf, int c, lzo_uint len); /* checksum functions */ LZO_EXTERN(lzo_uint32) -lzo_adler32(lzo_uint32 _adler, const lzo_bytep _buf, lzo_uint _len); + lzo_adler32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len); LZO_EXTERN(lzo_uint32) -lzo_crc32(lzo_uint32 _c, const lzo_bytep _buf, lzo_uint _len); + lzo_crc32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len); LZO_EXTERN(const lzo_uint32p) -lzo_get_crc32_table(void); + lzo_get_crc32_table(void); /* misc. */ LZO_EXTERN(int) _lzo_config_check(void); typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u; typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u; -typedef union { void *vp; lzo_bytep bp; lzo_uint32 u32; long l; } lzo_align_t; +typedef union { void *vp; lzo_bytep bp; lzo_uint u; lzo_uint32 u32; unsigned long l; } lzo_align_t; -/* align a char pointer on a boundary that is a multiple of `size' */ -LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size); -#define LZO_PTR_ALIGN_UP(_ptr,_size) \ - ((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size))) +/* align a char pointer on a boundary that is a multiple of 'size' */ +LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size); +#define LZO_PTR_ALIGN_UP(p,size) \ + ((p) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(p),(lzo_uint)(size))) /*********************************************************************** @@ -395,8 +424,8 @@ LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size); # define __LZO_WIN 1 #endif -#define __LZO_CMODEL -#define __LZO_DMODEL +#define __LZO_CMODEL /*empty*/ +#define __LZO_DMODEL /*empty*/ #define __LZO_ENTRY __LZO_CDECL #define LZO_EXTERN_CDECL LZO_EXTERN #define LZO_ALIGN LZO_PTR_ALIGN_UP diff --git a/extern/lzo/minilzo/lzodefs.h b/extern/lzo/minilzo/lzodefs.h index 180563723e5..0e40e332a8d 100644 --- a/extern/lzo/minilzo/lzodefs.h +++ b/extern/lzo/minilzo/lzodefs.h @@ -2,6 +2,9 @@ This file is part of the LZO real-time data compression library. + Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer @@ -121,7 +124,7 @@ #endif #if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL) # define ptrdiff_t long -# define _PTRDIFF_T_DEFINED +# define _PTRDIFF_T_DEFINED 1 #endif #if (UINT_MAX == LZO_0xffffL) # undef __LZO_RENAME_A @@ -265,9 +268,9 @@ # define LZO_EXTERN_C extern #endif #if !defined(__LZO_OS_OVERRIDE) -#if defined(LZO_OS_FREESTANDING) +#if (LZO_OS_FREESTANDING) # define LZO_INFO_OS "freestanding" -#elif defined(LZO_OS_EMBEDDED) +#elif (LZO_OS_EMBEDDED) # define LZO_INFO_OS "embedded" #elif 1 && defined(__IAR_SYSTEMS_ICC__) # define LZO_OS_EMBEDDED 1 @@ -476,12 +479,27 @@ # define LZO_CC_PELLESC 1 # define LZO_INFO_CC "Pelles C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__) -#elif defined(__llvm__) && defined(__GNUC__) && defined(__VERSION__) -# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) -# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +#elif defined(__clang__) && defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# if defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# else +# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# endif +# if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__) +# define LZO_CC_CLANG_CLANG (__clang_major__ * 0x10000L + __clang_minor__ * 0x100 + __clang_patchlevel__) +# else +# define LZO_CC_CLANG_CLANG 0x010000L +# endif +# define LZO_CC_CLANG LZO_CC_CLANG_GNUC +# define LZO_INFO_CC "clang" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# if defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) # else -# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) # endif +# define LZO_CC_LLVM LZO_CC_LLVM_GNUC # define LZO_INFO_CC "llvm-gcc" # define LZO_INFO_CCVER __VERSION__ #elif defined(__GNUC__) && defined(__VERSION__) @@ -502,6 +520,10 @@ # define LZO_CC_AZTECC 1 # define LZO_INFO_CC "Aztec C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__) +#elif defined(__CODEGEARC__) +# define LZO_CC_CODEGEARC 1 +# define LZO_INFO_CC "CodeGear C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CODEGEARC__) #elif defined(__BORLANDC__) # define LZO_CC_BORLANDC 1 # define LZO_INFO_CC "Borland C" @@ -632,7 +654,7 @@ #if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER) # error "LZO_CC_MSC: _MSC_FULL_VER is not defined" #endif -#if !defined(__LZO_ARCH_OVERRIDE) && !defined(LZO_ARCH_GENERIC) && defined(_CRAY) +#if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY) # if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY) # if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E) # define LZO_ARCH_CRAY_MPP 1 @@ -642,7 +664,7 @@ # endif #endif #if !defined(__LZO_ARCH_OVERRIDE) -#if defined(LZO_ARCH_GENERIC) +#if (LZO_ARCH_GENERIC) # define LZO_INFO_ARCH "generic" #elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) # define LZO_ARCH_I086 1 @@ -677,6 +699,9 @@ #elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) # define LZO_ARCH_AVR 1 # define LZO_INFO_ARCH "avr" +#elif defined(__avr32__) || defined(__AVR32__) +# define LZO_ARCH_AVR32 1 +# define LZO_INFO_ARCH "avr32" #elif defined(__bfin__) # define LZO_ARCH_BLACKFIN 1 # define LZO_INFO_ARCH "blackfin" @@ -799,10 +824,10 @@ # define LZO_ARCH_I086PM 1 # define LZO_ARCH_IA16PM 1 #endif -#if defined(LZO_ARCH_ARM_THUMB) && !defined(LZO_ARCH_ARM) +#if (LZO_ARCH_ARM_THUMB) && !(LZO_ARCH_ARM) # error "this should not happen" #endif -#if defined(LZO_ARCH_I086PM) && !defined(LZO_ARCH_I086) +#if (LZO_ARCH_I086PM) && !(LZO_ARCH_I086) # error "this should not happen" #endif #if (LZO_ARCH_I086) @@ -875,7 +900,7 @@ #elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295)) # undef LZO_HAVE_MM_HUGE_ARRAY #endif -#if (LZO_ARCH_I086PM) && !defined(LZO_HAVE_MM_HUGE_PTR) +#if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR) # if (LZO_OS_DOS16) # error "this should not happen" # elif (LZO_CC_ZORTECHC) @@ -1091,7 +1116,7 @@ extern "C" { #if (LZO_ARCH_I086 && LZO_CC_DMC) #elif (LZO_CC_CILLY) && defined(__GNUC__) # define LZO_SIZEOF_LONG_LONG 8 -#elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define LZO_SIZEOF_LONG_LONG 8 #elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400)) # define LZO_SIZEOF_LONG_LONG 8 @@ -1125,12 +1150,12 @@ extern "C" { #endif #endif #endif -#if defined(__cplusplus) && defined(LZO_CC_GNUC) +#if defined(__cplusplus) && (LZO_CC_GNUC) # if (LZO_CC_GNUC < 0x020800ul) # undef LZO_SIZEOF_LONG_LONG # endif #endif -#if defined(LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG) +#if (LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG) # undef LZO_SIZEOF_LONG_LONG #endif #if !defined(LZO_SIZEOF_VOID_P) @@ -1229,15 +1254,17 @@ extern "C" { # define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T #endif #endif -#if defined(LZO_ABI_NEUTRAL_ENDIAN) +#if (LZO_ABI_NEUTRAL_ENDIAN) # undef LZO_ABI_BIG_ENDIAN # undef LZO_ABI_LITTLE_ENDIAN -#elif !defined(LZO_ABI_BIG_ENDIAN) && !defined(LZO_ABI_LITTLE_ENDIAN) +#elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN) #if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP) # define LZO_ABI_BIG_ENDIAN 1 +#elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64) +# define LZO_ABI_LITTLE_ENDIAN 1 #elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430) # define LZO_ABI_LITTLE_ENDIAN 1 -#elif (LZO_ARCH_M68K || LZO_ARCH_S390) +#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390) # define LZO_ABI_BIG_ENDIAN 1 #elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__) # if (__LITTLE_ENDIAN__ == 1) @@ -1259,14 +1286,14 @@ extern "C" { # define LZO_ABI_LITTLE_ENDIAN 1 #endif #endif -#if defined(LZO_ABI_BIG_ENDIAN) && defined(LZO_ABI_LITTLE_ENDIAN) +#if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN) # error "this should not happen" #endif -#if defined(LZO_ABI_BIG_ENDIAN) +#if (LZO_ABI_BIG_ENDIAN) # define LZO_INFO_ABI_ENDIAN "be" -#elif defined(LZO_ABI_LITTLE_ENDIAN) +#elif (LZO_ABI_LITTLE_ENDIAN) # define LZO_INFO_ABI_ENDIAN "le" -#elif defined(LZO_ABI_NEUTRAL_ENDIAN) +#elif (LZO_ABI_NEUTRAL_ENDIAN) # define LZO_INFO_ABI_ENDIAN "neutral" #endif #if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) @@ -1292,15 +1319,15 @@ extern "C" { # define LZO_INFO_ABI_PM "ip32l64" #endif #if !defined(__LZO_LIBC_OVERRIDE) -#if defined(LZO_LIBC_NAKED) +#if (LZO_LIBC_NAKED) # define LZO_INFO_LIBC "naked" -#elif defined(LZO_LIBC_FREESTANDING) +#elif (LZO_LIBC_FREESTANDING) # define LZO_INFO_LIBC "freestanding" -#elif defined(LZO_LIBC_MOSTLY_FREESTANDING) +#elif (LZO_LIBC_MOSTLY_FREESTANDING) # define LZO_INFO_LIBC "mfreestanding" -#elif defined(LZO_LIBC_ISOC90) +#elif (LZO_LIBC_ISOC90) # define LZO_INFO_LIBC "isoc90" -#elif defined(LZO_LIBC_ISOC99) +#elif (LZO_LIBC_ISOC99) # define LZO_INFO_LIBC "isoc99" #elif defined(__dietlibc__) # define LZO_LIBC_DIETLIBC 1 @@ -1332,22 +1359,24 @@ extern "C" { #if !defined(__lzo_gnuc_extension__) #if (LZO_CC_GNUC >= 0x020800ul) # define __lzo_gnuc_extension__ __extension__ -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_gnuc_extension__ __extension__ #else -# define __lzo_gnuc_extension__ +# define __lzo_gnuc_extension__ /*empty*/ #endif #endif #if !defined(__lzo_ua_volatile) # define __lzo_ua_volatile volatile #endif #if !defined(__lzo_alignof) -#if (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +#if (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) # define __lzo_alignof(e) __alignof__(e) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700)) # define __lzo_alignof(e) __alignof__(e) #elif (LZO_CC_MSC && (_MSC_VER >= 1300)) # define __lzo_alignof(e) __alignof(e) +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_alignof(e) __alignof__(e) #endif #endif #if defined(__lzo_alignof) @@ -1358,7 +1387,7 @@ extern "C" { # define __lzo_constructor __attribute__((__constructor__,__used__)) #elif (LZO_CC_GNUC >= 0x020700ul) # define __lzo_constructor __attribute__((__constructor__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_constructor __attribute__((__constructor__)) #endif #endif @@ -1370,14 +1399,14 @@ extern "C" { # define __lzo_destructor __attribute__((__destructor__,__used__)) #elif (LZO_CC_GNUC >= 0x020700ul) # define __lzo_destructor __attribute__((__destructor__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_destructor __attribute__((__destructor__)) #endif #endif #if defined(__lzo_destructor) # define __lzo_HAVE_destructor 1 #endif -#if defined(__lzo_HAVE_destructor) && !defined(__lzo_HAVE_constructor) +#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor) # error "this should not happen" #endif #if !defined(__lzo_inline) @@ -1386,7 +1415,7 @@ extern "C" { # define __lzo_inline inline #elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550)) # define __lzo_inline __inline -#elif (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) # define __lzo_inline __inline__ #elif (LZO_CC_DMC) # define __lzo_inline __inline @@ -1396,6 +1425,8 @@ extern "C" { # define __lzo_inline __inline #elif (LZO_CC_MSC && (_MSC_VER >= 900)) # define __lzo_inline __inline +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_inline __inline__ #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) # define __lzo_inline inline #endif @@ -1403,7 +1434,7 @@ extern "C" { #if defined(__lzo_inline) # define __lzo_HAVE_inline 1 #else -# define __lzo_inline +# define __lzo_inline /*empty*/ #endif #if !defined(__lzo_forceinline) #if (LZO_CC_GNUC >= 0x030200ul) @@ -1412,16 +1443,18 @@ extern "C" { # define __lzo_forceinline __forceinline #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) # define __lzo_forceinline __inline__ __attribute__((__always_inline__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_forceinline __inline__ __attribute__((__always_inline__)) #elif (LZO_CC_MSC && (_MSC_VER >= 1200)) # define __lzo_forceinline __forceinline +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) #endif #endif #if defined(__lzo_forceinline) # define __lzo_HAVE_forceinline 1 #else -# define __lzo_forceinline +# define __lzo_forceinline /*empty*/ #endif #if !defined(__lzo_noinline) #if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul) @@ -1432,7 +1465,7 @@ extern "C" { # define __lzo_noinline __declspec(noinline) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) # define __lzo_noinline __attribute__((__noinline__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_noinline __attribute__((__noinline__)) #elif (LZO_CC_MSC && (_MSC_VER >= 1300)) # define __lzo_noinline __declspec(noinline) @@ -1441,14 +1474,16 @@ extern "C" { # else # define __lzo_noinline __declspec(noinline) # endif +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_noinline __attribute__((__noinline__)) #endif #endif #if defined(__lzo_noinline) # define __lzo_HAVE_noinline 1 #else -# define __lzo_noinline +# define __lzo_noinline /*empty*/ #endif -#if (defined(__lzo_HAVE_forceinline) || defined(__lzo_HAVE_noinline)) && !defined(__lzo_HAVE_inline) +#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline) # error "this should not happen" #endif #if !defined(__lzo_noreturn) @@ -1458,7 +1493,7 @@ extern "C" { # define __lzo_noreturn __declspec(noreturn) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) # define __lzo_noreturn __attribute__((__noreturn__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_noreturn __attribute__((__noreturn__)) #elif (LZO_CC_MSC && (_MSC_VER >= 1200)) # define __lzo_noreturn __declspec(noreturn) @@ -1467,16 +1502,16 @@ extern "C" { #if defined(__lzo_noreturn) # define __lzo_HAVE_noreturn 1 #else -# define __lzo_noreturn +# define __lzo_noreturn /*empty*/ #endif #if !defined(__lzo_nothrow) #if (LZO_CC_GNUC >= 0x030300ul) # define __lzo_nothrow __attribute__((__nothrow__)) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus) # define __lzo_nothrow __declspec(nothrow) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 900) && LZO_CC_SYNTAX_GNUC) # define __lzo_nothrow __attribute__((__nothrow__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_nothrow __attribute__((__nothrow__)) #elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus) # define __lzo_nothrow __declspec(nothrow) @@ -1485,14 +1520,14 @@ extern "C" { #if defined(__lzo_nothrow) # define __lzo_HAVE_nothrow 1 #else -# define __lzo_nothrow +# define __lzo_nothrow /*empty*/ #endif #if !defined(__lzo_restrict) #if (LZO_CC_GNUC >= 0x030400ul) # define __lzo_restrict __restrict__ #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) # define __lzo_restrict __restrict__ -#elif (LZO_CC_LLVM) +#elif (LZO_CC_CLANG || LZO_CC_LLVM) # define __lzo_restrict __restrict__ #elif (LZO_CC_MSC && (_MSC_VER >= 1400)) # define __lzo_restrict __restrict @@ -1501,7 +1536,7 @@ extern "C" { #if defined(__lzo_restrict) # define __lzo_HAVE_restrict 1 #else -# define __lzo_restrict +# define __lzo_restrict /*empty*/ #endif #if !defined(__lzo_likely) && !defined(__lzo_unlikely) #if (LZO_CC_GNUC >= 0x030200ul) @@ -1510,7 +1545,7 @@ extern "C" { #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) # define __lzo_likely(e) (__builtin_expect(!!(e),1)) # define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_likely(e) (__builtin_expect(!!(e),1)) # define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) #endif @@ -1530,7 +1565,7 @@ extern "C" { # define LZO_UNUSED(var) ((void) &var) # elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC) # define LZO_UNUSED(var) if (&var) ; else -# elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define LZO_UNUSED(var) ((void) var) # elif (LZO_CC_MSC && (_MSC_VER < 900)) # define LZO_UNUSED(var) if (&var) ; else @@ -1549,7 +1584,7 @@ extern "C" { # define LZO_UNUSED_FUNC(func) ((void) func) # elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC) # define LZO_UNUSED_FUNC(func) if (func) ; else -# elif (LZO_CC_LLVM) +# elif (LZO_CC_CLANG || LZO_CC_LLVM) # define LZO_UNUSED_FUNC(func) ((void) &func) # elif (LZO_CC_MSC && (_MSC_VER < 900)) # define LZO_UNUSED_FUNC(func) if (func) ; else @@ -1564,7 +1599,7 @@ extern "C" { #if !defined(LZO_UNUSED_LABEL) # if (LZO_CC_WATCOMC) && defined(__cplusplus) # define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l -# elif (LZO_CC_INTELC || LZO_CC_WATCOMC) +# elif (LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC) # define LZO_UNUSED_LABEL(l) if (0) goto l # else # define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l @@ -1579,6 +1614,15 @@ extern "C" { # define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init # endif #endif +#if !defined(LZO_UNCONST_CAST) +# if 0 && defined(__cplusplus) +# define LZO_UNCONST_CAST(t,e) (const_cast (e)) +# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((lzo_uintptr_t) ((const void *) (e)))))) +# else +# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((const void *) (e))))) +# endif +#endif #if !defined(LZO_COMPILE_TIME_ASSERT_HEADER) # if (LZO_CC_AZTECC || LZO_CC_ZORTECHC) # define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; @@ -1607,7 +1651,7 @@ extern "C" { # if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) # elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) # define __lzo_cdecl __cdecl -# define __lzo_cdecl_atexit +# define __lzo_cdecl_atexit /*empty*/ # define __lzo_cdecl_main __cdecl # if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) # define __lzo_cdecl_qsort __pascal @@ -1648,24 +1692,24 @@ extern "C" { # define __lzo_cdecl cdecl #endif #if !defined(__lzo_cdecl) -# define __lzo_cdecl +# define __lzo_cdecl /*empty*/ #endif #if !defined(__lzo_cdecl_atexit) -# define __lzo_cdecl_atexit +# define __lzo_cdecl_atexit /*empty*/ #endif #if !defined(__lzo_cdecl_main) -# define __lzo_cdecl_main +# define __lzo_cdecl_main /*empty*/ #endif #if !defined(__lzo_cdecl_qsort) -# define __lzo_cdecl_qsort +# define __lzo_cdecl_qsort /*empty*/ #endif #if !defined(__lzo_cdecl_sighandler) -# define __lzo_cdecl_sighandler +# define __lzo_cdecl_sighandler /*empty*/ #endif #if !defined(__lzo_cdecl_va) # define __lzo_cdecl_va __lzo_cdecl #endif -#if !defined(LZO_CFG_NO_WINDOWS_H) +#if !(LZO_CFG_NO_WINDOWS_H) #if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) # if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) # elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__) @@ -1711,7 +1755,7 @@ extern "C" { #elif (LZO_ARCH_POWERPC) # define LZO_OPT_PREFER_PREINC 1 # define LZO_OPT_PREFER_PREDEC 1 -# if defined(LZO_ABI_BIG_ENDIAN) +# if (LZO_ABI_BIG_ENDIAN) # define LZO_OPT_UNALIGNED16 1 # define LZO_OPT_UNALIGNED32 1 # endif @@ -1725,28 +1769,29 @@ extern "C" { # define LZO_OPT_PREFER_POSTINC 1 # define LZO_OPT_PREFER_PREDEC 1 #endif -#if !defined(LZO_CFG_NO_INLINE_ASM) -#if defined(LZO_CC_LLVM) +#ifndef LZO_CFG_NO_INLINE_ASM +#if (LZO_CC_LLVM) # define LZO_CFG_NO_INLINE_ASM 1 #endif #endif -#if !defined(LZO_CFG_NO_UNALIGNED) -#if defined(LZO_ABI_NEUTRAL_ENDIAN) || defined(LZO_ARCH_GENERIC) +#ifndef LZO_CFG_NO_UNALIGNED +#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC) # define LZO_CFG_NO_UNALIGNED 1 #endif #endif -#if defined(LZO_CFG_NO_UNALIGNED) +#if (LZO_CFG_NO_UNALIGNED) # undef LZO_OPT_UNALIGNED16 # undef LZO_OPT_UNALIGNED32 # undef LZO_OPT_UNALIGNED64 #endif -#if defined(LZO_CFG_NO_INLINE_ASM) +#if (LZO_CFG_NO_INLINE_ASM) #elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) # define LZO_ASM_SYNTAX_MSC 1 #elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) -#elif (LZO_ARCH_I386 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul)) +#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) # define LZO_ASM_SYNTAX_GNUC 1 -#elif (LZO_ARCH_AMD64 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) # define LZO_ASM_SYNTAX_GNUC 1 #endif #if (LZO_ASM_SYNTAX_GNUC) diff --git a/extern/lzo/minilzo/minilzo.c b/extern/lzo/minilzo/minilzo.c index 6a62b31b94a..34ce0f090bd 100644 --- a/extern/lzo/minilzo/minilzo.c +++ b/extern/lzo/minilzo/minilzo.c @@ -2,6 +2,9 @@ This file is part of the LZO real-time data compression library. + Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer @@ -43,8 +46,7 @@ * http://www.oberhumer.com/opensource/lzo/ */ -#define __LZO_IN_MINILZO -#define LZO_BUILD +#define __LZO_IN_MINILZO 1 #if defined(LZO_CFG_FREESTANDING) # undef MINILZO_HAVE_CONFIG_H @@ -142,7 +144,7 @@ #endif #if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL) # define ptrdiff_t long -# define _PTRDIFF_T_DEFINED +# define _PTRDIFF_T_DEFINED 1 #endif #if (UINT_MAX == LZO_0xffffL) # undef __LZO_RENAME_A @@ -286,9 +288,9 @@ # define LZO_EXTERN_C extern #endif #if !defined(__LZO_OS_OVERRIDE) -#if defined(LZO_OS_FREESTANDING) +#if (LZO_OS_FREESTANDING) # define LZO_INFO_OS "freestanding" -#elif defined(LZO_OS_EMBEDDED) +#elif (LZO_OS_EMBEDDED) # define LZO_INFO_OS "embedded" #elif 1 && defined(__IAR_SYSTEMS_ICC__) # define LZO_OS_EMBEDDED 1 @@ -497,12 +499,27 @@ # define LZO_CC_PELLESC 1 # define LZO_INFO_CC "Pelles C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__) -#elif defined(__llvm__) && defined(__GNUC__) && defined(__VERSION__) -# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) -# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +#elif defined(__clang__) && defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# if defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# else +# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# endif +# if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__) +# define LZO_CC_CLANG_CLANG (__clang_major__ * 0x10000L + __clang_minor__ * 0x100 + __clang_patchlevel__) # else -# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# define LZO_CC_CLANG_CLANG 0x010000L # endif +# define LZO_CC_CLANG LZO_CC_CLANG_GNUC +# define LZO_INFO_CC "clang" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# if defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# else +# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# endif +# define LZO_CC_LLVM LZO_CC_LLVM_GNUC # define LZO_INFO_CC "llvm-gcc" # define LZO_INFO_CCVER __VERSION__ #elif defined(__GNUC__) && defined(__VERSION__) @@ -523,6 +540,10 @@ # define LZO_CC_AZTECC 1 # define LZO_INFO_CC "Aztec C" # define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__) +#elif defined(__CODEGEARC__) +# define LZO_CC_CODEGEARC 1 +# define LZO_INFO_CC "CodeGear C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CODEGEARC__) #elif defined(__BORLANDC__) # define LZO_CC_BORLANDC 1 # define LZO_INFO_CC "Borland C" @@ -653,7 +674,7 @@ #if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER) # error "LZO_CC_MSC: _MSC_FULL_VER is not defined" #endif -#if !defined(__LZO_ARCH_OVERRIDE) && !defined(LZO_ARCH_GENERIC) && defined(_CRAY) +#if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY) # if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY) # if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E) # define LZO_ARCH_CRAY_MPP 1 @@ -663,7 +684,7 @@ # endif #endif #if !defined(__LZO_ARCH_OVERRIDE) -#if defined(LZO_ARCH_GENERIC) +#if (LZO_ARCH_GENERIC) # define LZO_INFO_ARCH "generic" #elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) # define LZO_ARCH_I086 1 @@ -698,6 +719,9 @@ #elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) # define LZO_ARCH_AVR 1 # define LZO_INFO_ARCH "avr" +#elif defined(__avr32__) || defined(__AVR32__) +# define LZO_ARCH_AVR32 1 +# define LZO_INFO_ARCH "avr32" #elif defined(__bfin__) # define LZO_ARCH_BLACKFIN 1 # define LZO_INFO_ARCH "blackfin" @@ -820,10 +844,10 @@ # define LZO_ARCH_I086PM 1 # define LZO_ARCH_IA16PM 1 #endif -#if defined(LZO_ARCH_ARM_THUMB) && !defined(LZO_ARCH_ARM) +#if (LZO_ARCH_ARM_THUMB) && !(LZO_ARCH_ARM) # error "this should not happen" #endif -#if defined(LZO_ARCH_I086PM) && !defined(LZO_ARCH_I086) +#if (LZO_ARCH_I086PM) && !(LZO_ARCH_I086) # error "this should not happen" #endif #if (LZO_ARCH_I086) @@ -896,7 +920,7 @@ #elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295)) # undef LZO_HAVE_MM_HUGE_ARRAY #endif -#if (LZO_ARCH_I086PM) && !defined(LZO_HAVE_MM_HUGE_PTR) +#if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR) # if (LZO_OS_DOS16) # error "this should not happen" # elif (LZO_CC_ZORTECHC) @@ -1112,7 +1136,7 @@ extern "C" { #if (LZO_ARCH_I086 && LZO_CC_DMC) #elif (LZO_CC_CILLY) && defined(__GNUC__) # define LZO_SIZEOF_LONG_LONG 8 -#elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define LZO_SIZEOF_LONG_LONG 8 #elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400)) # define LZO_SIZEOF_LONG_LONG 8 @@ -1146,12 +1170,12 @@ extern "C" { #endif #endif #endif -#if defined(__cplusplus) && defined(LZO_CC_GNUC) +#if defined(__cplusplus) && (LZO_CC_GNUC) # if (LZO_CC_GNUC < 0x020800ul) # undef LZO_SIZEOF_LONG_LONG # endif #endif -#if defined(LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG) +#if (LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG) # undef LZO_SIZEOF_LONG_LONG #endif #if !defined(LZO_SIZEOF_VOID_P) @@ -1250,15 +1274,17 @@ extern "C" { # define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T #endif #endif -#if defined(LZO_ABI_NEUTRAL_ENDIAN) +#if (LZO_ABI_NEUTRAL_ENDIAN) # undef LZO_ABI_BIG_ENDIAN # undef LZO_ABI_LITTLE_ENDIAN -#elif !defined(LZO_ABI_BIG_ENDIAN) && !defined(LZO_ABI_LITTLE_ENDIAN) +#elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN) #if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP) # define LZO_ABI_BIG_ENDIAN 1 +#elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64) +# define LZO_ABI_LITTLE_ENDIAN 1 #elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430) # define LZO_ABI_LITTLE_ENDIAN 1 -#elif (LZO_ARCH_M68K || LZO_ARCH_S390) +#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390) # define LZO_ABI_BIG_ENDIAN 1 #elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__) # if (__LITTLE_ENDIAN__ == 1) @@ -1280,14 +1306,14 @@ extern "C" { # define LZO_ABI_LITTLE_ENDIAN 1 #endif #endif -#if defined(LZO_ABI_BIG_ENDIAN) && defined(LZO_ABI_LITTLE_ENDIAN) +#if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN) # error "this should not happen" #endif -#if defined(LZO_ABI_BIG_ENDIAN) +#if (LZO_ABI_BIG_ENDIAN) # define LZO_INFO_ABI_ENDIAN "be" -#elif defined(LZO_ABI_LITTLE_ENDIAN) +#elif (LZO_ABI_LITTLE_ENDIAN) # define LZO_INFO_ABI_ENDIAN "le" -#elif defined(LZO_ABI_NEUTRAL_ENDIAN) +#elif (LZO_ABI_NEUTRAL_ENDIAN) # define LZO_INFO_ABI_ENDIAN "neutral" #endif #if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) @@ -1313,15 +1339,15 @@ extern "C" { # define LZO_INFO_ABI_PM "ip32l64" #endif #if !defined(__LZO_LIBC_OVERRIDE) -#if defined(LZO_LIBC_NAKED) +#if (LZO_LIBC_NAKED) # define LZO_INFO_LIBC "naked" -#elif defined(LZO_LIBC_FREESTANDING) +#elif (LZO_LIBC_FREESTANDING) # define LZO_INFO_LIBC "freestanding" -#elif defined(LZO_LIBC_MOSTLY_FREESTANDING) +#elif (LZO_LIBC_MOSTLY_FREESTANDING) # define LZO_INFO_LIBC "mfreestanding" -#elif defined(LZO_LIBC_ISOC90) +#elif (LZO_LIBC_ISOC90) # define LZO_INFO_LIBC "isoc90" -#elif defined(LZO_LIBC_ISOC99) +#elif (LZO_LIBC_ISOC99) # define LZO_INFO_LIBC "isoc99" #elif defined(__dietlibc__) # define LZO_LIBC_DIETLIBC 1 @@ -1353,22 +1379,24 @@ extern "C" { #if !defined(__lzo_gnuc_extension__) #if (LZO_CC_GNUC >= 0x020800ul) # define __lzo_gnuc_extension__ __extension__ -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_gnuc_extension__ __extension__ #else -# define __lzo_gnuc_extension__ +# define __lzo_gnuc_extension__ /*empty*/ #endif #endif #if !defined(__lzo_ua_volatile) # define __lzo_ua_volatile volatile #endif #if !defined(__lzo_alignof) -#if (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +#if (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) # define __lzo_alignof(e) __alignof__(e) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700)) # define __lzo_alignof(e) __alignof__(e) #elif (LZO_CC_MSC && (_MSC_VER >= 1300)) # define __lzo_alignof(e) __alignof(e) +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_alignof(e) __alignof__(e) #endif #endif #if defined(__lzo_alignof) @@ -1379,7 +1407,7 @@ extern "C" { # define __lzo_constructor __attribute__((__constructor__,__used__)) #elif (LZO_CC_GNUC >= 0x020700ul) # define __lzo_constructor __attribute__((__constructor__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_constructor __attribute__((__constructor__)) #endif #endif @@ -1391,14 +1419,14 @@ extern "C" { # define __lzo_destructor __attribute__((__destructor__,__used__)) #elif (LZO_CC_GNUC >= 0x020700ul) # define __lzo_destructor __attribute__((__destructor__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_destructor __attribute__((__destructor__)) #endif #endif #if defined(__lzo_destructor) # define __lzo_HAVE_destructor 1 #endif -#if defined(__lzo_HAVE_destructor) && !defined(__lzo_HAVE_constructor) +#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor) # error "this should not happen" #endif #if !defined(__lzo_inline) @@ -1407,7 +1435,7 @@ extern "C" { # define __lzo_inline inline #elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550)) # define __lzo_inline __inline -#elif (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) # define __lzo_inline __inline__ #elif (LZO_CC_DMC) # define __lzo_inline __inline @@ -1417,6 +1445,8 @@ extern "C" { # define __lzo_inline __inline #elif (LZO_CC_MSC && (_MSC_VER >= 900)) # define __lzo_inline __inline +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_inline __inline__ #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) # define __lzo_inline inline #endif @@ -1424,7 +1454,7 @@ extern "C" { #if defined(__lzo_inline) # define __lzo_HAVE_inline 1 #else -# define __lzo_inline +# define __lzo_inline /*empty*/ #endif #if !defined(__lzo_forceinline) #if (LZO_CC_GNUC >= 0x030200ul) @@ -1433,16 +1463,18 @@ extern "C" { # define __lzo_forceinline __forceinline #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) # define __lzo_forceinline __inline__ __attribute__((__always_inline__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_forceinline __inline__ __attribute__((__always_inline__)) #elif (LZO_CC_MSC && (_MSC_VER >= 1200)) # define __lzo_forceinline __forceinline +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) #endif #endif #if defined(__lzo_forceinline) # define __lzo_HAVE_forceinline 1 #else -# define __lzo_forceinline +# define __lzo_forceinline /*empty*/ #endif #if !defined(__lzo_noinline) #if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul) @@ -1453,7 +1485,7 @@ extern "C" { # define __lzo_noinline __declspec(noinline) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) # define __lzo_noinline __attribute__((__noinline__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_noinline __attribute__((__noinline__)) #elif (LZO_CC_MSC && (_MSC_VER >= 1300)) # define __lzo_noinline __declspec(noinline) @@ -1462,14 +1494,16 @@ extern "C" { # else # define __lzo_noinline __declspec(noinline) # endif +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_noinline __attribute__((__noinline__)) #endif #endif #if defined(__lzo_noinline) # define __lzo_HAVE_noinline 1 #else -# define __lzo_noinline +# define __lzo_noinline /*empty*/ #endif -#if (defined(__lzo_HAVE_forceinline) || defined(__lzo_HAVE_noinline)) && !defined(__lzo_HAVE_inline) +#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline) # error "this should not happen" #endif #if !defined(__lzo_noreturn) @@ -1479,7 +1513,7 @@ extern "C" { # define __lzo_noreturn __declspec(noreturn) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) # define __lzo_noreturn __attribute__((__noreturn__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_noreturn __attribute__((__noreturn__)) #elif (LZO_CC_MSC && (_MSC_VER >= 1200)) # define __lzo_noreturn __declspec(noreturn) @@ -1488,16 +1522,16 @@ extern "C" { #if defined(__lzo_noreturn) # define __lzo_HAVE_noreturn 1 #else -# define __lzo_noreturn +# define __lzo_noreturn /*empty*/ #endif #if !defined(__lzo_nothrow) #if (LZO_CC_GNUC >= 0x030300ul) # define __lzo_nothrow __attribute__((__nothrow__)) #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus) # define __lzo_nothrow __declspec(nothrow) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 900) && LZO_CC_SYNTAX_GNUC) # define __lzo_nothrow __attribute__((__nothrow__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_nothrow __attribute__((__nothrow__)) #elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus) # define __lzo_nothrow __declspec(nothrow) @@ -1506,14 +1540,14 @@ extern "C" { #if defined(__lzo_nothrow) # define __lzo_HAVE_nothrow 1 #else -# define __lzo_nothrow +# define __lzo_nothrow /*empty*/ #endif #if !defined(__lzo_restrict) #if (LZO_CC_GNUC >= 0x030400ul) # define __lzo_restrict __restrict__ #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) # define __lzo_restrict __restrict__ -#elif (LZO_CC_LLVM) +#elif (LZO_CC_CLANG || LZO_CC_LLVM) # define __lzo_restrict __restrict__ #elif (LZO_CC_MSC && (_MSC_VER >= 1400)) # define __lzo_restrict __restrict @@ -1522,7 +1556,7 @@ extern "C" { #if defined(__lzo_restrict) # define __lzo_HAVE_restrict 1 #else -# define __lzo_restrict +# define __lzo_restrict /*empty*/ #endif #if !defined(__lzo_likely) && !defined(__lzo_unlikely) #if (LZO_CC_GNUC >= 0x030200ul) @@ -1531,7 +1565,7 @@ extern "C" { #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) # define __lzo_likely(e) (__builtin_expect(!!(e),1)) # define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define __lzo_likely(e) (__builtin_expect(!!(e),1)) # define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) #endif @@ -1551,7 +1585,7 @@ extern "C" { # define LZO_UNUSED(var) ((void) &var) # elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC) # define LZO_UNUSED(var) if (&var) ; else -# elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) # define LZO_UNUSED(var) ((void) var) # elif (LZO_CC_MSC && (_MSC_VER < 900)) # define LZO_UNUSED(var) if (&var) ; else @@ -1570,7 +1604,7 @@ extern "C" { # define LZO_UNUSED_FUNC(func) ((void) func) # elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC) # define LZO_UNUSED_FUNC(func) if (func) ; else -# elif (LZO_CC_LLVM) +# elif (LZO_CC_CLANG || LZO_CC_LLVM) # define LZO_UNUSED_FUNC(func) ((void) &func) # elif (LZO_CC_MSC && (_MSC_VER < 900)) # define LZO_UNUSED_FUNC(func) if (func) ; else @@ -1585,7 +1619,7 @@ extern "C" { #if !defined(LZO_UNUSED_LABEL) # if (LZO_CC_WATCOMC) && defined(__cplusplus) # define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l -# elif (LZO_CC_INTELC || LZO_CC_WATCOMC) +# elif (LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC) # define LZO_UNUSED_LABEL(l) if (0) goto l # else # define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l @@ -1600,6 +1634,15 @@ extern "C" { # define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init # endif #endif +#if !defined(LZO_UNCONST_CAST) +# if 0 && defined(__cplusplus) +# define LZO_UNCONST_CAST(t,e) (const_cast (e)) +# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((lzo_uintptr_t) ((const void *) (e)))))) +# else +# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((const void *) (e))))) +# endif +#endif #if !defined(LZO_COMPILE_TIME_ASSERT_HEADER) # if (LZO_CC_AZTECC || LZO_CC_ZORTECHC) # define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; @@ -1628,7 +1671,7 @@ extern "C" { # if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) # elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) # define __lzo_cdecl __cdecl -# define __lzo_cdecl_atexit +# define __lzo_cdecl_atexit /*empty*/ # define __lzo_cdecl_main __cdecl # if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) # define __lzo_cdecl_qsort __pascal @@ -1669,24 +1712,24 @@ extern "C" { # define __lzo_cdecl cdecl #endif #if !defined(__lzo_cdecl) -# define __lzo_cdecl +# define __lzo_cdecl /*empty*/ #endif #if !defined(__lzo_cdecl_atexit) -# define __lzo_cdecl_atexit +# define __lzo_cdecl_atexit /*empty*/ #endif #if !defined(__lzo_cdecl_main) -# define __lzo_cdecl_main +# define __lzo_cdecl_main /*empty*/ #endif #if !defined(__lzo_cdecl_qsort) -# define __lzo_cdecl_qsort +# define __lzo_cdecl_qsort /*empty*/ #endif #if !defined(__lzo_cdecl_sighandler) -# define __lzo_cdecl_sighandler +# define __lzo_cdecl_sighandler /*empty*/ #endif #if !defined(__lzo_cdecl_va) # define __lzo_cdecl_va __lzo_cdecl #endif -#if !defined(LZO_CFG_NO_WINDOWS_H) +#if !(LZO_CFG_NO_WINDOWS_H) #if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) # if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) # elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__) @@ -1732,7 +1775,7 @@ extern "C" { #elif (LZO_ARCH_POWERPC) # define LZO_OPT_PREFER_PREINC 1 # define LZO_OPT_PREFER_PREDEC 1 -# if defined(LZO_ABI_BIG_ENDIAN) +# if (LZO_ABI_BIG_ENDIAN) # define LZO_OPT_UNALIGNED16 1 # define LZO_OPT_UNALIGNED32 1 # endif @@ -1746,28 +1789,29 @@ extern "C" { # define LZO_OPT_PREFER_POSTINC 1 # define LZO_OPT_PREFER_PREDEC 1 #endif -#if !defined(LZO_CFG_NO_INLINE_ASM) -#if defined(LZO_CC_LLVM) +#ifndef LZO_CFG_NO_INLINE_ASM +#if (LZO_CC_LLVM) # define LZO_CFG_NO_INLINE_ASM 1 #endif #endif -#if !defined(LZO_CFG_NO_UNALIGNED) -#if defined(LZO_ABI_NEUTRAL_ENDIAN) || defined(LZO_ARCH_GENERIC) +#ifndef LZO_CFG_NO_UNALIGNED +#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC) # define LZO_CFG_NO_UNALIGNED 1 #endif #endif -#if defined(LZO_CFG_NO_UNALIGNED) +#if (LZO_CFG_NO_UNALIGNED) # undef LZO_OPT_UNALIGNED16 # undef LZO_OPT_UNALIGNED32 # undef LZO_OPT_UNALIGNED64 #endif -#if defined(LZO_CFG_NO_INLINE_ASM) +#if (LZO_CFG_NO_INLINE_ASM) #elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) # define LZO_ASM_SYNTAX_MSC 1 #elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) -#elif (LZO_ARCH_I386 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul)) +#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) # define LZO_ASM_SYNTAX_GNUC 1 -#elif (LZO_ARCH_AMD64 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) # define LZO_ASM_SYNTAX_GNUC 1 #endif #if (LZO_ASM_SYNTAX_GNUC) @@ -1830,34 +1874,34 @@ extern "C" { #undef LZO_HAVE_CONFIG_H #include "minilzo.h" -#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2030) +#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2060) # error "version mismatch in miniLZO source files" #endif #ifdef MINILZO_HAVE_CONFIG_H -# define LZO_HAVE_CONFIG_H +# define LZO_HAVE_CONFIG_H 1 #endif #ifndef __LZO_CONF_H -#define __LZO_CONF_H +#define __LZO_CONF_H 1 #if !defined(__LZO_IN_MINILZO) -#if defined(LZO_CFG_FREESTANDING) +#if (LZO_CFG_FREESTANDING) # define LZO_LIBC_FREESTANDING 1 # define LZO_OS_FREESTANDING 1 # define ACC_LIBC_FREESTANDING 1 # define ACC_OS_FREESTANDING 1 #endif -#if defined(LZO_CFG_NO_UNALIGNED) +#if (LZO_CFG_NO_UNALIGNED) # define ACC_CFG_NO_UNALIGNED 1 #endif -#if defined(LZO_ARCH_GENERIC) +#if (LZO_ARCH_GENERIC) # define ACC_ARCH_GENERIC 1 #endif -#if defined(LZO_ABI_NEUTRAL_ENDIAN) +#if (LZO_ABI_NEUTRAL_ENDIAN) # define ACC_ABI_NEUTRAL_ENDIAN 1 #endif -#if defined(LZO_HAVE_CONFIG_H) +#if (LZO_HAVE_CONFIG_H) # define ACC_CONFIG_NO_HEADER 1 #endif #if defined(LZO_CFG_EXTRA_CONFIG_HEADER) @@ -1886,11 +1930,14 @@ extern "C" { #endif #if (LZO_CC_SUNPROC) +#if !defined(__cplusplus) # pragma error_messages(off,E_END_OF_LOOP_CODE_NOT_REACHED) # pragma error_messages(off,E_LOOP_NOT_ENTERED_AT_TOP) +# pragma error_messages(off,E_STATEMENT_NOT_REACHED) +#endif #endif -#if defined(__LZO_MMODEL_HUGE) && (!LZO_HAVE_MM_HUGE_PTR) +#if (__LZO_MMODEL_HUGE) && !(LZO_HAVE_MM_HUGE_PTR) # error "this should not happen - check defines for __huge" #endif @@ -1955,40 +2002,44 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp)) #include #endif -#if defined(LZO_CFG_FREESTANDING) +#if (LZO_CFG_FREESTANDING) # undef HAVE_MEMCMP # undef HAVE_MEMCPY # undef HAVE_MEMMOVE # undef HAVE_MEMSET #endif -#if !defined(HAVE_MEMCMP) +#if !(HAVE_MEMCMP) # undef memcmp # define memcmp(a,b,c) lzo_memcmp(a,b,c) -#elif !defined(__LZO_MMODEL_HUGE) +#elif !(__LZO_MMODEL_HUGE) +# undef lzo_memcmp # define lzo_memcmp(a,b,c) memcmp(a,b,c) #endif -#if !defined(HAVE_MEMCPY) +#if !(HAVE_MEMCPY) # undef memcpy # define memcpy(a,b,c) lzo_memcpy(a,b,c) -#elif !defined(__LZO_MMODEL_HUGE) +#elif !(__LZO_MMODEL_HUGE) +# undef lzo_memcpy # define lzo_memcpy(a,b,c) memcpy(a,b,c) #endif -#if !defined(HAVE_MEMMOVE) +#if !(HAVE_MEMMOVE) # undef memmove # define memmove(a,b,c) lzo_memmove(a,b,c) -#elif !defined(__LZO_MMODEL_HUGE) +#elif !(__LZO_MMODEL_HUGE) +# undef lzo_memmove # define lzo_memmove(a,b,c) memmove(a,b,c) #endif -#if !defined(HAVE_MEMSET) +#if !(HAVE_MEMSET) # undef memset # define memset(a,b,c) lzo_memset(a,b,c) -#elif !defined(__LZO_MMODEL_HUGE) +#elif !(__LZO_MMODEL_HUGE) +# undef lzo_memset # define lzo_memset(a,b,c) memset(a,b,c) #endif #undef NDEBUG -#if defined(LZO_CFG_FREESTANDING) +#if (LZO_CFG_FREESTANDING) # undef LZO_DEBUG # define NDEBUG 1 # undef assert @@ -2008,13 +2059,24 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp)) #endif #if !defined(__lzo_inline) -# define __lzo_inline +# define __lzo_inline /*empty*/ #endif #if !defined(__lzo_forceinline) -# define __lzo_forceinline +# define __lzo_forceinline /*empty*/ #endif #if !defined(__lzo_noinline) -# define __lzo_noinline +# define __lzo_noinline /*empty*/ +#endif + +#if (LZO_CFG_PGO) +# undef __acc_likely +# undef __acc_unlikely +# undef __lzo_likely +# undef __lzo_unlikely +# define __acc_likely(e) (e) +# define __acc_unlikely(e) (e) +# define __lzo_likely(e) (e) +# define __lzo_unlikely(e) (e) #endif #if 1 @@ -2050,24 +2112,69 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp)) #endif #endif -#if 1 && !defined(LZO_CFG_NO_UNALIGNED) -#if 1 && (LZO_ARCH_AMD64 || LZO_ARCH_I386) +#if 1 && (LZO_ARCH_AMD64 || LZO_ARCH_I386 || LZO_ARCH_POWERPC) # if (LZO_SIZEOF_SHORT == 2) -# define LZO_UNALIGNED_OK_2 +# define LZO_UNALIGNED_OK_2 1 # endif # if (LZO_SIZEOF_INT == 4) -# define LZO_UNALIGNED_OK_4 +# define LZO_UNALIGNED_OK_4 1 # endif #endif +#if 1 && (LZO_ARCH_AMD64) +# if defined(LZO_UINT64_MAX) +# define LZO_UNALIGNED_OK_8 1 +# endif #endif - +#if (LZO_CFG_NO_UNALIGNED) +# undef LZO_UNALIGNED_OK_2 +# undef LZO_UNALIGNED_OK_4 +# undef LZO_UNALIGNED_OK_8 +#endif + +#undef UA_GET16 +#undef UA_SET16 +#undef UA_COPY16 +#undef UA_GET32 +#undef UA_SET32 +#undef UA_COPY32 +#undef UA_GET64 +#undef UA_SET64 +#undef UA_COPY64 #if defined(LZO_UNALIGNED_OK_2) - LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(short) == 2) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(unsigned short) == 2) +# if 1 && defined(ACC_UA_COPY16) +# define UA_GET16 ACC_UA_GET16 +# define UA_SET16 ACC_UA_SET16 +# define UA_COPY16 ACC_UA_COPY16 +# else +# define UA_GET16(p) (* (__lzo_ua_volatile const lzo_ushortp) (__lzo_ua_volatile const lzo_voidp) (p)) +# define UA_SET16(p,v) ((* (__lzo_ua_volatile lzo_ushortp) (__lzo_ua_volatile lzo_voidp) (p)) = (unsigned short) (v)) +# define UA_COPY16(d,s) UA_SET16(d, UA_GET16(s)) +# endif #endif -#if defined(LZO_UNALIGNED_OK_4) - LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4) -#elif defined(LZO_ALIGNED_OK_4) - LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4) +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4) +# if 1 && defined(ACC_UA_COPY32) +# define UA_GET32 ACC_UA_GET32 +# define UA_SET32 ACC_UA_SET32 +# define UA_COPY32 ACC_UA_COPY32 +# else +# define UA_GET32(p) (* (__lzo_ua_volatile const lzo_uint32p) (__lzo_ua_volatile const lzo_voidp) (p)) +# define UA_SET32(p,v) ((* (__lzo_ua_volatile lzo_uint32p) (__lzo_ua_volatile lzo_voidp) (p)) = (lzo_uint32) (v)) +# define UA_COPY32(d,s) UA_SET32(d, UA_GET32(s)) +# endif +#endif +#if defined(LZO_UNALIGNED_OK_8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint64) == 8) +# if 1 && defined(ACC_UA_COPY64) +# define UA_GET64 ACC_UA_GET64 +# define UA_SET64 ACC_UA_SET64 +# define UA_COPY64 ACC_UA_COPY64 +# else +# define UA_GET64(p) (* (__lzo_ua_volatile const lzo_uint64p) (__lzo_ua_volatile const lzo_voidp) (p)) +# define UA_SET64(p,v) ((* (__lzo_ua_volatile lzo_uint64p) (__lzo_ua_volatile lzo_voidp) (p)) = (lzo_uint64) (v)) +# define UA_COPY64(d,s) UA_SET64(d, UA_GET64(s)) +# endif #endif #define MEMCPY8_DS(dest,src,len) \ @@ -2079,19 +2186,17 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp)) #define MEMCPY_DS(dest,src,len) \ do *dest++ = *src++; while (--len > 0) -__LZO_EXTERN_C int __lzo_init_done; -__LZO_EXTERN_C const char __lzo_copyright[]; LZO_EXTERN(const lzo_bytep) lzo_copyright(void); #ifndef __LZO_PTR_H -#define __LZO_PTR_H +#define __LZO_PTR_H 1 #ifdef __cplusplus extern "C" { #endif #if !defined(lzo_uintptr_t) -# if defined(__LZO_MMODEL_HUGE) +# if (__LZO_MMODEL_HUGE) # define lzo_uintptr_t unsigned long # else # define lzo_uintptr_t acc_uintptr_t @@ -2140,6 +2245,10 @@ typedef union lzo_uint a_lzo_uint; lzo_int32 a_lzo_int32; lzo_uint32 a_lzo_uint32; +#if defined(LZO_UINT64_MAX) + lzo_int64 a_lzo_int64; + lzo_uint64 a_lzo_uint64; +#endif ptrdiff_t a_ptrdiff_t; lzo_uintptr_t a_lzo_uintptr_t; lzo_voidp a_lzo_voidp; @@ -2161,14 +2270,19 @@ lzo_full_align_t; #endif -#define LZO_DETERMINISTIC +#ifndef LZO_DETERMINISTIC +#define LZO_DETERMINISTIC 1 +#endif -#define LZO_DICT_USE_PTR +#ifndef LZO_DICT_USE_PTR +#define LZO_DICT_USE_PTR 1 #if 0 && (LZO_ARCH_I086) # undef LZO_DICT_USE_PTR +# define LZO_DICT_USE_PTR 0 +#endif #endif -#if defined(LZO_DICT_USE_PTR) +#if (LZO_DICT_USE_PTR) # define lzo_dict_t const lzo_bytep # define lzo_dict_p lzo_dict_t __LZO_MMODEL * #else @@ -2216,22 +2330,22 @@ __lzo_align_gap(const lzo_voidp ptr, lzo_uint size) } #endif +#if !defined(MINILZO_CFG_SKIP_LZO_UTIL) /* If you use the LZO library in a product, I would appreciate that you * keep this copyright string in the executable of your product. */ -const char __lzo_copyright[] = +static const char __lzo_copyright[] = #if !defined(__LZO_IN_MINLZO) LZO_VERSION_STRING; #else "\r\n\n" "LZO data compression library.\n" - "$Copyright: LZO (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Markus Franz Xaver Johannes Oberhumer\n" + "$Copyright: LZO Copyright (C) 1996-2011 Markus Franz Xaver Johannes Oberhumer\n" "\n" "http://www.oberhumer.com $\n\n" "$Id: LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE " $\n" - "$Built: " __DATE__ " " __TIME__ " $\n" "$Info: " LZO_INFO_STRING " $\n"; #endif @@ -2321,6 +2435,7 @@ lzo_adler32(lzo_uint32 adler, const lzo_bytep buf, lzo_uint len) #undef LZO_DO8 #undef LZO_DO16 +#endif #if !defined(MINILZO_CFG_SKIP_LZO_STRING) #undef lzo_memcmp #undef lzo_memcpy @@ -2343,7 +2458,7 @@ lzo_adler32(lzo_uint32 adler, const lzo_bytep buf, lzo_uint len) #endif LZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo_hsize_t len) { -#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMCMP) +#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCMP) const lzo_hbyte_p p1 = (const lzo_hbyte_p) s1; const lzo_hbyte_p p2 = (const lzo_hbyte_p) s2; if __lzo_likely(len > 0) do @@ -2360,7 +2475,7 @@ LZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo } LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len) { -#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMCPY) +#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCPY) lzo_hbyte_p p1 = (lzo_hbyte_p) dest; const lzo_hbyte_p p2 = (const lzo_hbyte_p) src; if (!(len > 0) || p1 == p2) @@ -2375,7 +2490,7 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src } LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len) { -#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMMOVE) +#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMMOVE) lzo_hbyte_p p1 = (lzo_hbyte_p) dest; const lzo_hbyte_p p2 = (const lzo_hbyte_p) src; if (!(len > 0) || p1 == p2) @@ -2401,7 +2516,7 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p sr } LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len) { -#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMSET) +#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMSET) lzo_hbyte_p p = (lzo_hbyte_p) s; if __lzo_likely(len > 0) do *p++ = (unsigned char) c; @@ -2413,6 +2528,7 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len) } #undef LZOLIB_PUBLIC #endif +#if !defined(MINILZO_CFG_SKIP_LZO_INIT) #if !defined(__LZO_IN_MINILZO) @@ -2426,6 +2542,11 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len) ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint32) ACCCHK_ASSERT((LZO_UINT32_C(1) << (int)(8*sizeof(LZO_UINT32_C(1))-1)) > 0) ACCCHK_ASSERT(sizeof(lzo_uint32) >= 4) +#if defined(LZO_UINT64_MAX) + ACCCHK_ASSERT(sizeof(lzo_uint64) == 8) + ACCCHK_ASSERT_IS_SIGNED_T(lzo_int64) + ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint64) +#endif #if !defined(__LZO_UINTPTR_T_IS_POINTER) ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uintptr_t) @@ -2440,40 +2561,158 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len) #endif #undef ACCCHK_ASSERT +#define WANT_lzo_bitops_clz32 1 +#define WANT_lzo_bitops_clz64 1 +#define WANT_lzo_bitops_ctz32 1 +#define WANT_lzo_bitops_ctz64 1 + +#if (defined(_WIN32) || defined(_WIN64)) && ((LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_MSC && (_MSC_VER >= 1400))) +#include +#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) && 0 +#pragma intrinsic(_BitScanReverse) +static __lzo_inline unsigned lzo_bitops_clz32(lzo_uint32 v) +{ + unsigned long r; + (void) _BitScanReverse(&r, v); + return (unsigned) r; +} +#define lzo_bitops_clz32 lzo_bitops_clz32 +#endif +#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) && 0 +#pragma intrinsic(_BitScanReverse64) +static __lzo_inline unsigned lzo_bitops_clz64(lzo_uint64 v) +{ + unsigned long r; + (void) _BitScanReverse64(&r, v); + return (unsigned) r; +} +#define lzo_bitops_clz64 lzo_bitops_clz64 +#endif +#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32) +#pragma intrinsic(_BitScanForward) +static __lzo_inline unsigned lzo_bitops_ctz32(lzo_uint32 v) +{ + unsigned long r; + (void) _BitScanForward(&r, v); + return (unsigned) r; +} +#define lzo_bitops_ctz32 lzo_bitops_ctz32 +#endif +#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX) +#pragma intrinsic(_BitScanForward64) +static __lzo_inline unsigned lzo_bitops_ctz64(lzo_uint64 v) +{ + unsigned long r; + (void) _BitScanForward64(&r, v); + return (unsigned) r; +} +#define lzo_bitops_ctz64 lzo_bitops_ctz64 +#endif + +#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_LLVM && (!defined(__llvm_tools_version__) || (__llvm_tools_version__+0 >= 0x010500ul)))) +#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) +#define lzo_bitops_clz32(v) ((unsigned) __builtin_clz(v)) +#endif +#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_clz64(v) ((unsigned) __builtin_clzll(v)) +#endif +#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32) +#define lzo_bitops_ctz32(v) ((unsigned) __builtin_ctz(v)) +#endif +#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_ctz64(v) ((unsigned) __builtin_ctzll(v)) +#endif +#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount32) +#define lzo_bitops_popcount32(v) ((unsigned) __builtin_popcount(v)) +#endif +#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_popcount64(v) ((unsigned) __builtin_popcountll(v)) +#endif +#endif + +#if 0 +#define u2p(ptr,off) ((lzo_voidp) (((lzo_bytep)(lzo_voidp)(ptr)) + (off))) +#else +static __lzo_noinline lzo_voidp u2p(lzo_voidp ptr, lzo_uint off) +{ + return (lzo_voidp) ((lzo_bytep) ptr + off); +} +#endif + LZO_PUBLIC(int) _lzo_config_check(void) { lzo_bool r = 1; - union { unsigned char c[2*sizeof(lzo_xint)]; lzo_xint l[2]; } u; - lzo_uintptr_t p; - + union { + lzo_xint a[2]; unsigned char b[2*LZO_MAX(8,sizeof(lzo_xint))]; +#if defined(LZO_UNALIGNED_OK_8) + lzo_uint64 c[2]; +#endif + unsigned short x[2]; lzo_uint32 y[2]; lzo_uint z[2]; + } u; + lzo_voidp p; + + u.a[0] = u.a[1] = 0; + p = u2p(&u, 0); + r &= ((* (lzo_bytep) p) == 0); #if !defined(LZO_CFG_NO_CONFIG_CHECK) #if defined(LZO_ABI_BIG_ENDIAN) - u.l[0] = u.l[1] = 0; u.c[sizeof(lzo_xint) - 1] = 128; - r &= (u.l[0] == 128); + u.a[0] = u.a[1] = 0; u.b[sizeof(lzo_uint) - 1] = 128; + p = u2p(&u, 0); + r &= ((* (lzo_uintp) p) == 128); #endif #if defined(LZO_ABI_LITTLE_ENDIAN) - u.l[0] = u.l[1] = 0; u.c[0] = 128; - r &= (u.l[0] == 128); + u.a[0] = u.a[1] = 0; u.b[0] = 128; + p = u2p(&u, 0); + r &= ((* (lzo_uintp) p) == 128); #endif #if defined(LZO_UNALIGNED_OK_2) - p = (lzo_uintptr_t) (const lzo_voidp) &u.c[0]; - u.l[0] = u.l[1] = 0; - r &= ((* (const lzo_ushortp) (p+1)) == 0); + u.a[0] = u.a[1] = 0; + u.b[0] = 1; u.b[sizeof(unsigned short) + 1] = 2; + p = u2p(&u, 1); + r &= ((* (lzo_ushortp) p) == 0); #endif #if defined(LZO_UNALIGNED_OK_4) - p = (lzo_uintptr_t) (const lzo_voidp) &u.c[0]; - u.l[0] = u.l[1] = 0; - r &= ((* (const lzo_uint32p) (p+1)) == 0); + u.a[0] = u.a[1] = 0; + u.b[0] = 3; u.b[sizeof(lzo_uint32) + 1] = 4; + p = u2p(&u, 1); + r &= ((* (lzo_uint32p) p) == 0); +#endif +#if defined(LZO_UNALIGNED_OK_8) + u.c[0] = u.c[1] = 0; + u.b[0] = 5; u.b[sizeof(lzo_uint64) + 1] = 6; + p = u2p(&u, 1); + r &= ((* (lzo_uint64p) p) == 0); +#endif +#if defined(lzo_bitops_clz32) + { unsigned i; lzo_uint32 v = 1; + for (i = 0; i < 32; i++, v <<= 1) + r &= lzo_bitops_clz32(v) == 31 - i; + } +#endif +#if defined(lzo_bitops_clz64) + { unsigned i; lzo_uint64 v = 1; + for (i = 0; i < 64; i++, v <<= 1) + r &= lzo_bitops_clz64(v) == 63 - i; + } +#endif +#if defined(lzo_bitops_ctz32) + { unsigned i; lzo_uint32 v = 1; + for (i = 0; i < 32; i++, v <<= 1) + r &= lzo_bitops_ctz32(v) == i; + } +#endif +#if defined(lzo_bitops_ctz64) + { unsigned i; lzo_uint64 v = 1; + for (i = 0; i < 64; i++, v <<= 1) + r &= lzo_bitops_ctz64(v) == i; + } #endif #endif - LZO_UNUSED(u); LZO_UNUSED(p); return r == 1 ? LZO_E_OK : LZO_E_ERROR; } -int __lzo_init_done = 0; - LZO_PUBLIC(int) __lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5, int s6, int s7, int s8, int s9) @@ -2489,8 +2728,6 @@ __lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5, #endif #undef ACCCHK_ASSERT - __lzo_init_done = 1; - if (v == 0) return LZO_E_ERROR; @@ -2532,27 +2769,47 @@ int __far __pascal LibMain ( int a, short b, short c, long d ) #endif -#define do_compress _lzo1x_1_do_compress +#endif + +#define LZO1X 1 +#define LZO_EOF_CODE 1 +#define M2_MAX_OFFSET 0x0800 #if !defined(MINILZO_CFG_SKIP_LZO1X_1_COMPRESS) -#define LZO_NEED_DICT_H +#if 1 && defined(UA_GET32) +#undef LZO_DICT_USE_PTR +#define LZO_DICT_USE_PTR 0 +#undef lzo_dict_t +#define lzo_dict_t unsigned short +#endif + +#define LZO_NEED_DICT_H 1 +#ifndef D_BITS #define D_BITS 14 +#endif #define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) #define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) +#if 1 +#define DINDEX(dv,p) DM(((DMUL(0x1824429d,dv)) >> (32-D_BITS))) +#else +#define DINDEX(dv,p) DM((dv) + ((dv) >> (32-D_BITS))) +#endif #ifndef __LZO_CONFIG1X_H -#define __LZO_CONFIG1X_H +#define __LZO_CONFIG1X_H 1 #if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z) -# define LZO1X +# define LZO1X 1 #endif #if !defined(__LZO_IN_MINILZO) #include "lzo/lzo1x.h" #endif -#define LZO_EOF_CODE +#ifndef LZO_EOF_CODE +#define LZO_EOF_CODE 1 +#endif #undef LZO_DETERMINISTIC #define M1_MAX_OFFSET 0x0400 @@ -2592,7 +2849,7 @@ int __far __pascal LibMain ( int a, short b, short c, long d ) #define DL_MIN_LEN M2_MIN_LEN #ifndef __LZO_DICT_H -#define __LZO_DICT_H +#define __LZO_DICT_H 1 #ifdef __cplusplus extern "C" { @@ -2633,10 +2890,10 @@ extern "C" { #if (D_BITS != DL_BITS + DD_BITS) # error "D_BITS does not match" #endif -#if (D_BITS < 8 || D_BITS > 18) +#if (D_BITS < 6 || D_BITS > 18) # error "invalid D_BITS" #endif -#if (DL_BITS < 8 || DL_BITS > 20) +#if (DL_BITS < 6 || DL_BITS > 20) # error "invalid DL_BITS" #endif #if (DD_BITS < 0 || DD_BITS > 6) @@ -2695,14 +2952,14 @@ extern "C" { # define _DINDEX(dv,p) (_DV_A((p),DL_SHIFT)) #elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL) -# define __LZO_HASH_INCREMENTAL +# define __LZO_HASH_INCREMENTAL 1 # define DVAL_FIRST(dv,p) dv = _DV_A((p),DL_SHIFT) # define DVAL_NEXT(dv,p) dv = (((dv) << DL_SHIFT) ^ p[2]) # define _DINDEX(dv,p) (dv) # define DVAL_LOOKAHEAD DL_MIN_LEN #elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A) -# define __LZO_HASH_INCREMENTAL +# define __LZO_HASH_INCREMENTAL 1 # define DVAL_FIRST(dv,p) dv = _DV_A((p),5) # define DVAL_NEXT(dv,p) \ dv ^= (lzo_xint)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2]) @@ -2710,7 +2967,7 @@ extern "C" { # define DVAL_LOOKAHEAD DL_MIN_LEN #elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B) -# define __LZO_HASH_INCREMENTAL +# define __LZO_HASH_INCREMENTAL 1 # define DVAL_FIRST(dv,p) dv = _DV_B((p),5) # define DVAL_NEXT(dv,p) \ dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_xint)(p[2]) << (2*5))) @@ -2739,7 +2996,12 @@ extern "C" { #if !defined(DVAL_ASSERT) #if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG) -static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p) +#if (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_LLVM) +static void __attribute__((__unused__)) +#else +static void +#endif +DVAL_ASSERT(lzo_xint dv, const lzo_bytep p) { lzo_xint df; DVAL_FIRST(df,(p)); @@ -2750,11 +3012,11 @@ static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p) #endif #endif -#if defined(LZO_DICT_USE_PTR) +#if (LZO_DICT_USE_PTR) # define DENTRY(p,in) (p) # define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex] #else -# define DENTRY(p,in) ((lzo_uint) ((p)-(in))) +# define DENTRY(p,in) ((lzo_dict_t) pd(p, in)) # define GINDEX(m_pos,m_off,dict,dindex,in) m_off = dict[dindex] #endif @@ -2775,7 +3037,7 @@ static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p) #endif -#if defined(LZO_DICT_USE_PTR) +#if (LZO_DICT_USE_PTR) #define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \ (m_pos == NULL || (m_off = pd(ip, m_pos)) > max_offset) @@ -2784,7 +3046,7 @@ static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p) (BOUNDS_CHECKING_OFF_IN_EXPR(( \ m_pos = ip - (lzo_uint) PTR_DIFF(ip,m_pos), \ PTR_LT(m_pos,in) || \ - (m_off = (lzo_uint) PTR_DIFF(ip,m_pos)) <= 0 || \ + (m_off = (lzo_uint) PTR_DIFF(ip,m_pos)) == 0 || \ m_off > max_offset ))) #else @@ -2801,7 +3063,7 @@ static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p) #endif -#if defined(LZO_DETERMINISTIC) +#if (LZO_DETERMINISTIC) # define LZO_CHECK_MPOS LZO_CHECK_MPOS_DET #else # define LZO_CHECK_MPOS LZO_CHECK_MPOS_NON_DET @@ -2817,17 +3079,99 @@ static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p) #endif +#define LZO_DETERMINISTIC !(LZO_DICT_USE_PTR) + +#ifndef DO_COMPRESS #define DO_COMPRESS lzo1x_1_compress +#endif + +#if 1 && defined(DO_COMPRESS) && !defined(do_compress) +# define do_compress LZO_CPP_ECONCAT2(DO_COMPRESS,_core) +#endif + +#if defined(UA_GET64) && (LZO_ABI_BIG_ENDIAN) +# define WANT_lzo_bitops_clz64 1 +#elif defined(UA_GET64) && (LZO_ABI_LITTLE_ENDIAN) +# define WANT_lzo_bitops_ctz64 1 +#elif defined(UA_GET32) && (LZO_ABI_BIG_ENDIAN) +# define WANT_lzo_bitops_clz32 1 +#elif defined(UA_GET32) && (LZO_ABI_LITTLE_ENDIAN) +# define WANT_lzo_bitops_ctz32 1 +#endif + +#if (defined(_WIN32) || defined(_WIN64)) && ((LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_MSC && (_MSC_VER >= 1400))) +#include +#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) && 0 +#pragma intrinsic(_BitScanReverse) +static __lzo_inline unsigned lzo_bitops_clz32(lzo_uint32 v) +{ + unsigned long r; + (void) _BitScanReverse(&r, v); + return (unsigned) r; +} +#define lzo_bitops_clz32 lzo_bitops_clz32 +#endif +#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) && 0 +#pragma intrinsic(_BitScanReverse64) +static __lzo_inline unsigned lzo_bitops_clz64(lzo_uint64 v) +{ + unsigned long r; + (void) _BitScanReverse64(&r, v); + return (unsigned) r; +} +#define lzo_bitops_clz64 lzo_bitops_clz64 +#endif +#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32) +#pragma intrinsic(_BitScanForward) +static __lzo_inline unsigned lzo_bitops_ctz32(lzo_uint32 v) +{ + unsigned long r; + (void) _BitScanForward(&r, v); + return (unsigned) r; +} +#define lzo_bitops_ctz32 lzo_bitops_ctz32 +#endif +#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX) +#pragma intrinsic(_BitScanForward64) +static __lzo_inline unsigned lzo_bitops_ctz64(lzo_uint64 v) +{ + unsigned long r; + (void) _BitScanForward64(&r, v); + return (unsigned) r; +} +#define lzo_bitops_ctz64 lzo_bitops_ctz64 +#endif + +#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_LLVM && (!defined(__llvm_tools_version__) || (__llvm_tools_version__+0 >= 0x010500ul)))) +#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) +#define lzo_bitops_clz32(v) ((unsigned) __builtin_clz(v)) +#endif +#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_clz64(v) ((unsigned) __builtin_clzll(v)) +#endif +#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32) +#define lzo_bitops_ctz32(v) ((unsigned) __builtin_ctz(v)) +#endif +#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_ctz64(v) ((unsigned) __builtin_ctzll(v)) +#endif +#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount32) +#define lzo_bitops_popcount32(v) ((unsigned) __builtin_popcount(v)) +#endif +#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_popcount64(v) ((unsigned) __builtin_popcountll(v)) +#endif +#endif static __lzo_noinline lzo_uint do_compress ( const lzo_bytep in , lzo_uint in_len, lzo_bytep out, lzo_uintp out_len, - lzo_voidp wrkmem ) + lzo_uint ti, lzo_voidp wrkmem) { register const lzo_bytep ip; lzo_bytep op; const lzo_bytep const in_end = in + in_len; - const lzo_bytep const ip_end = in + in_len - M2_MAX_LEN - 5; + const lzo_bytep const ip_end = in + in_len - 20; const lzo_bytep ii; lzo_dict_p const dict = (lzo_dict_p) wrkmem; @@ -2835,14 +3179,17 @@ do_compress ( const lzo_bytep in , lzo_uint in_len, ip = in; ii = ip; - ip += 4; + ip += ti < 4 ? 4 - ti : 0; for (;;) { - register const lzo_bytep m_pos; - lzo_uint m_off; + const lzo_bytep m_pos; +#if !(LZO_DETERMINISTIC) + LZO_DEFINE_UNINITIALIZED_VAR(lzo_uint, m_off, 0); lzo_uint m_len; lzo_uint dindex; - +next: + if __lzo_unlikely(ip >= ip_end) + break; DINDEX1(dindex,ip); GINDEX(m_pos,m_off,dict,dindex,in); if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) @@ -2860,200 +3207,245 @@ do_compress ( const lzo_bytep in , lzo_uint in_len, goto literal; try_match: -#if 1 && defined(LZO_UNALIGNED_OK_2) - if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip) +#if defined(UA_GET32) + if (UA_GET32(m_pos) != UA_GET32(ip)) #else - if (m_pos[0] != ip[0] || m_pos[1] != ip[1]) + if (m_pos[0] != ip[0] || m_pos[1] != ip[1] || m_pos[2] != ip[2] || m_pos[3] != ip[3]) #endif { +literal: + UPDATE_I(dict,0,dindex,ip,in); + ip += 1 + ((ip - ii) >> 5); + continue; } - else - { - if __lzo_likely(m_pos[2] == ip[2]) - { -#if 0 - if (m_off <= M2_MAX_OFFSET) - goto match; - if (lit <= 3) - goto match; - if (lit == 3) - { - assert(op - 2 > out); op[-2] |= LZO_BYTE(3); - *op++ = *ii++; *op++ = *ii++; *op++ = *ii++; - goto code_match; - } - if (m_pos[3] == ip[3]) -#endif - goto match; - } - else - { -#if 0 -#if 0 - if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3) + UPDATE_I(dict,0,dindex,ip,in); #else - if (m_off <= M1_MAX_OFFSET && lit == 3) -#endif - { - register lzo_uint t; - - t = lit; - assert(op - 2 > out); op[-2] |= LZO_BYTE(t); - do *op++ = *ii++; while (--t > 0); - assert(ii == ip); - m_off -= 1; - *op++ = LZO_BYTE(M1_MARKER | ((m_off & 3) << 2)); - *op++ = LZO_BYTE(m_off >> 2); - ip += 2; - goto match_done; - } -#endif - } - } - + lzo_uint m_off; + lzo_uint m_len; + { + lzo_uint32 dv; + lzo_uint dindex; literal: - UPDATE_I(dict,0,dindex,ip,in); - ++ip; + ip += 1 + ((ip - ii) >> 5); +next: if __lzo_unlikely(ip >= ip_end) break; - continue; - -match: + dv = UA_GET32(ip); + dindex = DINDEX(dv,ip); + GINDEX(m_off,m_pos,in+dict,dindex,in); UPDATE_I(dict,0,dindex,ip,in); - if (pd(ip,ii) > 0) - { - register lzo_uint t = pd(ip,ii); + if __lzo_unlikely(dv != UA_GET32(m_pos)) + goto literal; + } +#endif + ii -= ti; ti = 0; + { + register lzo_uint t = pd(ip,ii); + if (t != 0) + { if (t <= 3) { - assert(op - 2 > out); op[-2] |= LZO_BYTE(t); +#if defined(UA_COPY32) + UA_COPY32(op, ii); + op += t; +#else + { do *op++ = *ii++; while (--t > 0); } +#endif } - else if (t <= 18) +#if defined(UA_COPY32) || defined(UA_COPY64) + else if (t <= 16) + { *op++ = LZO_BYTE(t - 3); +#if defined(UA_COPY64) + UA_COPY64(op, ii); + UA_COPY64(op+8, ii+8); +#else + UA_COPY32(op, ii); + UA_COPY32(op+4, ii+4); + UA_COPY32(op+8, ii+8); + UA_COPY32(op+12, ii+12); +#endif + op += t; + } +#endif else { - register lzo_uint tt = t - 18; - - *op++ = 0; - while (tt > 255) + if (t <= 18) + *op++ = LZO_BYTE(t - 3); + else { - tt -= 255; + register lzo_uint tt = t - 18; *op++ = 0; + while __lzo_unlikely(tt > 255) + { + tt -= 255; +#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400)) + * (volatile unsigned char *) op++ = 0; +#else + *op++ = 0; +#endif + } + assert(tt > 0); + *op++ = LZO_BYTE(tt); } - assert(tt > 0); - *op++ = LZO_BYTE(tt); +#if defined(UA_COPY32) || defined(UA_COPY64) + do { +#if defined(UA_COPY64) + UA_COPY64(op, ii); + UA_COPY64(op+8, ii+8); +#else + UA_COPY32(op, ii); + UA_COPY32(op+4, ii+4); + UA_COPY32(op+8, ii+8); + UA_COPY32(op+12, ii+12); +#endif + op += 16; ii += 16; t -= 16; + } while (t >= 16); if (t > 0) +#endif + { do *op++ = *ii++; while (--t > 0); } } - do *op++ = *ii++; while (--t > 0); } - - assert(ii == ip); - ip += 3; - if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ || - m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++ -#ifdef LZO1Y - || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++ - || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++ + } + m_len = 4; + { +#if defined(UA_GET64) + lzo_uint64 v; + v = UA_GET64(ip + m_len) ^ UA_GET64(m_pos + m_len); + if __lzo_unlikely(v == 0) { + do { + m_len += 8; + v = UA_GET64(ip + m_len) ^ UA_GET64(m_pos + m_len); + if __lzo_unlikely(ip + m_len >= ip_end) + goto m_len_done; + } while (v == 0); + } +#if (LZO_ABI_BIG_ENDIAN) && defined(lzo_bitops_clz64) + m_len += lzo_bitops_clz64(v) / CHAR_BIT; +#elif (LZO_ABI_BIG_ENDIAN) + if ((v >> (64 - CHAR_BIT)) == 0) do { + v <<= CHAR_BIT; + m_len += 1; + } while ((v >> (64 - CHAR_BIT)) == 0); +#elif (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_ctz64) + m_len += lzo_bitops_ctz64(v) / CHAR_BIT; +#elif (LZO_ABI_LITTLE_ENDIAN) + if ((v & UCHAR_MAX) == 0) do { + v >>= CHAR_BIT; + m_len += 1; + } while ((v & UCHAR_MAX) == 0); +#else + if (ip[m_len] == m_pos[m_len]) do { + m_len += 1; + } while (ip[m_len] == m_pos[m_len]); +#endif +#elif defined(UA_GET32) + lzo_uint32 v; + v = UA_GET32(ip + m_len) ^ UA_GET32(m_pos + m_len); + if __lzo_unlikely(v == 0) { + do { + m_len += 4; + v = UA_GET32(ip + m_len) ^ UA_GET32(m_pos + m_len); + if __lzo_unlikely(ip + m_len >= ip_end) + goto m_len_done; + } while (v == 0); + } +#if (LZO_ABI_BIG_ENDIAN) && defined(lzo_bitops_clz32) + m_len += lzo_bitops_clz32(v) / CHAR_BIT; +#elif (LZO_ABI_BIG_ENDIAN) + if ((v >> (32 - CHAR_BIT)) == 0) do { + v <<= CHAR_BIT; + m_len += 1; + } while ((v >> (32 - CHAR_BIT)) == 0); +#elif (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_ctz32) + m_len += lzo_bitops_ctz32(v) / CHAR_BIT; +#elif (LZO_ABI_LITTLE_ENDIAN) + if ((v & UCHAR_MAX) == 0) do { + v >>= CHAR_BIT; + m_len += 1; + } while ((v & UCHAR_MAX) == 0); +#else + if (ip[m_len] == m_pos[m_len]) do { + m_len += 1; + } while (ip[m_len] == m_pos[m_len]); +#endif +#else + if __lzo_unlikely(ip[m_len] == m_pos[m_len]) { + do { + m_len += 1; + if __lzo_unlikely(ip + m_len >= ip_end) + goto m_len_done; + } while (ip[m_len] == m_pos[m_len]); + } #endif - ) + } +m_len_done: + m_off = pd(ip,m_pos); + ip += m_len; + ii = ip; + if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) { - --ip; - m_len = pd(ip, ii); - assert(m_len >= 3); assert(m_len <= M2_MAX_LEN); - - if (m_off <= M2_MAX_OFFSET) - { - m_off -= 1; + m_off -= 1; #if defined(LZO1X) - *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2)); - *op++ = LZO_BYTE(m_off >> 3); + *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2)); + *op++ = LZO_BYTE(m_off >> 3); #elif defined(LZO1Y) - *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2)); - *op++ = LZO_BYTE(m_off >> 2); + *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2)); + *op++ = LZO_BYTE(m_off >> 2); #endif - } - else if (m_off <= M3_MAX_OFFSET) - { - m_off -= 1; + } + else if (m_off <= M3_MAX_OFFSET) + { + m_off -= 1; + if (m_len <= M3_MAX_LEN) *op++ = LZO_BYTE(M3_MARKER | (m_len - 2)); - goto m3_m4_offset; - } else -#if defined(LZO1X) { - m_off -= 0x4000; - assert(m_off > 0); assert(m_off <= 0x7fff); - *op++ = LZO_BYTE(M4_MARKER | - ((m_off & 0x4000) >> 11) | (m_len - 2)); - goto m3_m4_offset; - } -#elif defined(LZO1Y) - goto m4_match; + m_len -= M3_MAX_LEN; + *op++ = M3_MARKER | 0; + while __lzo_unlikely(m_len > 255) + { + m_len -= 255; +#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400)) + * (volatile unsigned char *) op++ = 0; +#else + *op++ = 0; #endif + } + *op++ = LZO_BYTE(m_len); + } + *op++ = LZO_BYTE(m_off << 2); + *op++ = LZO_BYTE(m_off >> 6); } else { - { - const lzo_bytep end = in_end; - const lzo_bytep m = m_pos + M2_MAX_LEN + 1; - while (ip < end && *m == *ip) - m++, ip++; - m_len = pd(ip, ii); - } - assert(m_len > M2_MAX_LEN); - - if (m_off <= M3_MAX_OFFSET) - { - m_off -= 1; - if (m_len <= 33) - *op++ = LZO_BYTE(M3_MARKER | (m_len - 2)); - else - { - m_len -= 33; - *op++ = M3_MARKER | 0; - goto m3_m4_len; - } - } + m_off -= 0x4000; + if (m_len <= M4_MAX_LEN) + *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8) | (m_len - 2)); else { -#if defined(LZO1Y) -m4_match: -#endif - m_off -= 0x4000; - assert(m_off > 0); assert(m_off <= 0x7fff); - if (m_len <= M4_MAX_LEN) - *op++ = LZO_BYTE(M4_MARKER | - ((m_off & 0x4000) >> 11) | (m_len - 2)); - else + m_len -= M4_MAX_LEN; + *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8)); + while __lzo_unlikely(m_len > 255) { - m_len -= M4_MAX_LEN; - *op++ = LZO_BYTE(M4_MARKER | ((m_off & 0x4000) >> 11)); -m3_m4_len: - while (m_len > 255) - { - m_len -= 255; - *op++ = 0; - } - assert(m_len > 0); - *op++ = LZO_BYTE(m_len); + m_len -= 255; +#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400)) + * (volatile unsigned char *) op++ = 0; +#else + *op++ = 0; +#endif } + *op++ = LZO_BYTE(m_len); } - -m3_m4_offset: - *op++ = LZO_BYTE((m_off & 63) << 2); + *op++ = LZO_BYTE(m_off << 2); *op++ = LZO_BYTE(m_off >> 6); } - -#if 0 -match_done: -#endif - ii = ip; - if __lzo_unlikely(ip >= ip_end) - break; + goto next; } *out_len = pd(op, out); - return pd(in_end,ii); + return pd(in_end,ii-ti); } LZO_PUBLIC(int) @@ -3061,16 +3453,30 @@ DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len, lzo_bytep out, lzo_uintp out_len, lzo_voidp wrkmem ) { + const lzo_bytep ip = in; lzo_bytep op = out; - lzo_uint t; + lzo_uint l = in_len; + lzo_uint t = 0; - if __lzo_unlikely(in_len <= M2_MAX_LEN + 5) - t = in_len; - else + while (l > 20) { - t = do_compress(in,in_len,op,out_len,wrkmem); + lzo_uint ll = l; + lzo_uintptr_t ll_end; +#if 0 || (LZO_DETERMINISTIC) + ll = LZO_MIN(ll, 49152); +#endif + ll_end = (lzo_uintptr_t)ip + ll; + if ((ll_end + ((t + ll) >> 5)) <= ll_end || (const lzo_bytep)(ll_end + ((t + ll) >> 5)) <= ip + ll) + break; +#if (LZO_DETERMINISTIC) + lzo_memset(wrkmem, 0, ((lzo_uint)1 << D_BITS) * sizeof(lzo_dict_t)); +#endif + t = do_compress(ip,ll,op,out_len,t,wrkmem); + ip += ll; op += *out_len; + l -= ll; } + t += l; if (t > 0) { @@ -3090,7 +3496,12 @@ DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len, while (tt > 255) { tt -= 255; +#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400)) + + * (volatile unsigned char *) op++ = 0; +#else *op++ = 0; +#endif } assert(tt > 0); *op++ = LZO_BYTE(tt); @@ -3126,7 +3537,7 @@ DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len, # define LZO_TEST_OVERRUN_OUTPUT 2 # endif # if !defined(LZO_TEST_OVERRUN_LOOKBEHIND) -# define LZO_TEST_OVERRUN_LOOKBEHIND +# define LZO_TEST_OVERRUN_LOOKBEHIND 1 # endif #endif @@ -3177,42 +3588,32 @@ DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len, #endif #if defined(TEST_IP) -# define HAVE_TEST_IP +# define HAVE_TEST_IP 1 #else # define TEST_IP 1 #endif #if defined(TEST_OP) -# define HAVE_TEST_OP +# define HAVE_TEST_OP 1 #else # define TEST_OP 1 #endif #if defined(NEED_IP) -# define HAVE_NEED_IP +# define HAVE_NEED_IP 1 #else # define NEED_IP(x) ((void) 0) #endif #if defined(NEED_OP) -# define HAVE_NEED_OP +# define HAVE_NEED_OP 1 #else # define NEED_OP(x) ((void) 0) #endif #if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP) -# define HAVE_ANY_IP +# define HAVE_ANY_IP 1 #endif #if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP) -# define HAVE_ANY_OP -#endif - -#undef __COPY4 -#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src) - -#undef COPY4 -#if defined(LZO_UNALIGNED_OK_4) -# define COPY4(dst,src) __COPY4(dst,src) -#elif defined(LZO_ALIGNED_OK_4) -# define COPY4(dst,src) __COPY4((lzo_uintptr_t)(dst),(lzo_uintptr_t)(src)) +# define HAVE_ANY_OP 1 #endif #if defined(DO_DECOMPRESS) @@ -3291,19 +3692,36 @@ DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, t += 15 + *ip++; } assert(t > 0); NEED_OP(t+3); NEED_IP(t+4); -#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4) + t += 3; + if (t >= 8) do + { + UA_COPY64(op,ip); + op += 8; ip += 8; t -= 8; + } while (t >= 8); + if (t >= 4) + { + UA_COPY32(op,ip); + op += 4; ip += 4; t -= 4; + } + if (t > 0) + { + *op++ = *ip++; + if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } + } +#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) #if !defined(LZO_UNALIGNED_OK_4) if (PTR_ALIGNED2_4(op,ip)) { #endif - COPY4(op,ip); + UA_COPY32(op,ip); op += 4; ip += 4; if (--t > 0) { if (t >= 4) { do { - COPY4(op,ip); + UA_COPY32(op,ip); op += 4; ip += 4; t -= 4; } while (t >= 4); if (t > 0) do *op++ = *ip++; while (--t > 0); @@ -3316,7 +3734,7 @@ DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, else #endif #endif -#if !defined(LZO_UNALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) && !defined(LZO_UNALIGNED_OK_8) { *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; do *op++ = *ip++; while (--t > 0); @@ -3437,7 +3855,7 @@ match: } #elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) m_pos = op - 1; - m_pos -= (* (const lzo_ushortp) ip) >> 2; + m_pos -= UA_GET16(ip) >> 2; #else m_pos = op - 1; m_pos -= (ip[0] >> 2) + (ip[1] << 6); @@ -3482,7 +3900,7 @@ match: #if defined(LZO1Z) m_pos -= (ip[0] << 6) + (ip[1] >> 2); #elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) - m_pos -= (* (const lzo_ushortp) ip) >> 2; + m_pos -= UA_GET16(ip) >> 2; #else m_pos -= (ip[0] >> 2) + (ip[1] << 6); #endif @@ -3530,7 +3948,28 @@ match: #else TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); -#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4) + if (op - m_pos >= 8) + { + t += (3 - 1); + if (t >= 8) do + { + UA_COPY64(op,m_pos); + op += 8; m_pos += 8; t -= 8; + } while (t >= 8); + if (t >= 4) + { + UA_COPY32(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } + if (t > 0) + { + *op++ = m_pos[0]; + if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } } + } + } + else +#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) #if !defined(LZO_UNALIGNED_OK_4) if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) { @@ -3539,10 +3978,10 @@ match: if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) { #endif - COPY4(op,m_pos); + UA_COPY32(op,m_pos); op += 4; m_pos += 4; t -= 4 - (3 - 1); do { - COPY4(op,m_pos); + UA_COPY32(op,m_pos); op += 4; m_pos += 4; t -= 4; } while (t >= 4); if (t > 0) do *op++ = *m_pos++; while (--t > 0); @@ -3610,7 +4049,7 @@ lookbehind_overrun: #endif -#define LZO_TEST_OVERRUN +#define LZO_TEST_OVERRUN 1 #undef DO_DECOMPRESS #define DO_DECOMPRESS lzo1x_decompress_safe @@ -3624,7 +4063,7 @@ lookbehind_overrun: # define LZO_TEST_OVERRUN_OUTPUT 2 # endif # if !defined(LZO_TEST_OVERRUN_LOOKBEHIND) -# define LZO_TEST_OVERRUN_LOOKBEHIND +# define LZO_TEST_OVERRUN_LOOKBEHIND 1 # endif #endif @@ -3675,42 +4114,32 @@ lookbehind_overrun: #endif #if defined(TEST_IP) -# define HAVE_TEST_IP +# define HAVE_TEST_IP 1 #else # define TEST_IP 1 #endif #if defined(TEST_OP) -# define HAVE_TEST_OP +# define HAVE_TEST_OP 1 #else # define TEST_OP 1 #endif #if defined(NEED_IP) -# define HAVE_NEED_IP +# define HAVE_NEED_IP 1 #else # define NEED_IP(x) ((void) 0) #endif #if defined(NEED_OP) -# define HAVE_NEED_OP +# define HAVE_NEED_OP 1 #else # define NEED_OP(x) ((void) 0) #endif #if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP) -# define HAVE_ANY_IP +# define HAVE_ANY_IP 1 #endif #if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP) -# define HAVE_ANY_OP -#endif - -#undef __COPY4 -#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src) - -#undef COPY4 -#if defined(LZO_UNALIGNED_OK_4) -# define COPY4(dst,src) __COPY4(dst,src) -#elif defined(LZO_ALIGNED_OK_4) -# define COPY4(dst,src) __COPY4((lzo_uintptr_t)(dst),(lzo_uintptr_t)(src)) +# define HAVE_ANY_OP 1 #endif #if defined(DO_DECOMPRESS) @@ -3789,19 +4218,36 @@ DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, t += 15 + *ip++; } assert(t > 0); NEED_OP(t+3); NEED_IP(t+4); -#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4) + t += 3; + if (t >= 8) do + { + UA_COPY64(op,ip); + op += 8; ip += 8; t -= 8; + } while (t >= 8); + if (t >= 4) + { + UA_COPY32(op,ip); + op += 4; ip += 4; t -= 4; + } + if (t > 0) + { + *op++ = *ip++; + if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } + } +#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) #if !defined(LZO_UNALIGNED_OK_4) if (PTR_ALIGNED2_4(op,ip)) { #endif - COPY4(op,ip); + UA_COPY32(op,ip); op += 4; ip += 4; if (--t > 0) { if (t >= 4) { do { - COPY4(op,ip); + UA_COPY32(op,ip); op += 4; ip += 4; t -= 4; } while (t >= 4); if (t > 0) do *op++ = *ip++; while (--t > 0); @@ -3814,7 +4260,7 @@ DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, else #endif #endif -#if !defined(LZO_UNALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) && !defined(LZO_UNALIGNED_OK_8) { *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; do *op++ = *ip++; while (--t > 0); @@ -3935,7 +4381,7 @@ match: } #elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) m_pos = op - 1; - m_pos -= (* (const lzo_ushortp) ip) >> 2; + m_pos -= UA_GET16(ip) >> 2; #else m_pos = op - 1; m_pos -= (ip[0] >> 2) + (ip[1] << 6); @@ -3980,7 +4426,7 @@ match: #if defined(LZO1Z) m_pos -= (ip[0] << 6) + (ip[1] >> 2); #elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) - m_pos -= (* (const lzo_ushortp) ip) >> 2; + m_pos -= UA_GET16(ip) >> 2; #else m_pos -= (ip[0] >> 2) + (ip[1] << 6); #endif @@ -4028,7 +4474,28 @@ match: #else TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); -#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4) + if (op - m_pos >= 8) + { + t += (3 - 1); + if (t >= 8) do + { + UA_COPY64(op,m_pos); + op += 8; m_pos += 8; t -= 8; + } while (t >= 8); + if (t >= 4) + { + UA_COPY32(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } + if (t > 0) + { + *op++ = m_pos[0]; + if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } } + } + } + else +#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) #if !defined(LZO_UNALIGNED_OK_4) if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) { @@ -4037,10 +4504,10 @@ match: if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) { #endif - COPY4(op,m_pos); + UA_COPY32(op,m_pos); op += 4; m_pos += 4; t -= 4 - (3 - 1); do { - COPY4(op,m_pos); + UA_COPY32(op,m_pos); op += 4; m_pos += 4; t -= 4; } while (t >= 4); if (t > 0) do *op++ = *m_pos++; while (--t > 0); diff --git a/extern/lzo/minilzo/minilzo.h b/extern/lzo/minilzo/minilzo.h index 93916bc89b2..f2c104856e3 100644 --- a/extern/lzo/minilzo/minilzo.h +++ b/extern/lzo/minilzo/minilzo.h @@ -2,6 +2,9 @@ This file is part of the LZO real-time data compression library. + Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer @@ -45,9 +48,9 @@ #ifndef __MINILZO_H -#define __MINILZO_H +#define __MINILZO_H 1 -#define MINILZO_VERSION 0x2030 +#define MINILZO_VERSION 0x2060 #ifdef __LZOCONF_H # error "you cannot use both LZO and miniLZO" @@ -103,7 +106,6 @@ lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len, #define LZO_HEAP_ALLOC(var,size) \ lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ] - #ifdef __cplusplus } /* extern "C" */ #endif -- cgit v1.2.3 From 66cca267b151f512ab9487615e86dd012423016b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 25 Feb 2013 08:59:26 +0000 Subject: Upgrade Ceres library to current master which is current 1.5RC This is helpful because it brings CHOLMOB-free ITERATIVE_SCHUR and SCHUR_JACOBI which is really nice for new upcoming bundle adjustment. If also includes all the local fixes we made locally. There're lots of other improvements/fixed which are not currently would be so much visible in Blender, but which opens doors for some great improvements in future. --- extern/libmv/third_party/ceres/CMakeLists.txt | 33 +- extern/libmv/third_party/ceres/ChangeLog | 730 +++++++------- extern/libmv/third_party/ceres/bundle.sh | 5 +- extern/libmv/third_party/ceres/files.txt | 33 +- .../ceres/include/ceres/autodiff_cost_function.h | 71 +- .../libmv/third_party/ceres/include/ceres/ceres.h | 8 + .../ceres/include/ceres/cost_function_to_functor.h | 752 ++++++++++++++ .../third_party/ceres/include/ceres/crs_matrix.h | 32 +- .../include/ceres/dynamic_autodiff_cost_function.h | 215 ++++ .../third_party/ceres/include/ceres/fpclassify.h | 2 + .../ceres/include/ceres/gradient_checker.h | 222 +++++ .../ceres/include/ceres/internal/autodiff.h | 158 +-- .../ceres/include/ceres/internal/fixed_array.h | 6 +- .../ceres/include/ceres/internal/macros.h | 12 +- .../include/ceres/internal/manual_constructor.h | 29 +- .../ceres/include/ceres/internal/numeric_diff.h | 199 ++++ .../ceres/include/ceres/internal/scoped_ptr.h | 15 +- .../include/ceres/internal/variadic_evaluate.h | 182 ++++ .../ceres/include/ceres/iteration_callback.h | 43 +- .../include/ceres/numeric_diff_cost_function.h | 374 +++---- .../ceres/include/ceres/numeric_diff_functor.h | 346 +++++++ .../ceres/include/ceres/ordered_groups.h | 176 ++++ .../third_party/ceres/include/ceres/problem.h | 156 ++- .../third_party/ceres/include/ceres/rotation.h | 196 +++- .../ceres/include/ceres/sized_cost_function.h | 30 +- .../libmv/third_party/ceres/include/ceres/solver.h | 313 ++++-- .../libmv/third_party/ceres/include/ceres/types.h | 110 ++- .../third_party/ceres/internal/ceres/array_utils.h | 2 +- .../internal/ceres/block_jacobi_preconditioner.cc | 20 +- .../internal/ceres/block_jacobi_preconditioner.h | 29 +- .../ceres/block_random_access_dense_matrix.cc | 2 +- .../ceres/block_random_access_sparse_matrix.cc | 2 +- .../internal/ceres/canonical_views_clustering.h | 6 +- .../ceres/internal/ceres/cgnr_solver.cc | 34 +- .../third_party/ceres/internal/ceres/cgnr_solver.h | 15 +- .../ceres/internal/ceres/collections_port.h | 2 +- .../ceres/compressed_row_jacobian_writer.cc | 3 +- .../internal/ceres/compressed_row_sparse_matrix.h | 9 +- .../internal/ceres/coordinate_descent_minimizer.cc | 236 +++++ .../internal/ceres/coordinate_descent_minimizer.h | 88 ++ .../third_party/ceres/internal/ceres/corrector.cc | 17 +- .../third_party/ceres/internal/ceres/cxsparse.cc | 10 +- .../third_party/ceres/internal/ceres/cxsparse.h | 5 +- .../ceres/internal/ceres/dense_jacobian_writer.h | 11 +- .../internal/ceres/dense_normal_cholesky_solver.cc | 13 +- .../ceres/internal/ceres/dense_qr_solver.cc | 29 +- .../ceres/internal/ceres/dense_qr_solver.h | 2 + .../ceres/internal/ceres/dense_sparse_matrix.cc | 16 +- .../ceres/internal/ceres/dense_sparse_matrix.h | 1 + .../ceres/internal/ceres/dogleg_strategy.cc | 18 +- .../ceres/internal/ceres/dogleg_strategy.h | 4 +- .../third_party/ceres/internal/ceres/evaluator.h | 17 +- .../ceres/internal/ceres/execution_summary.h | 90 ++ .../libmv/third_party/ceres/internal/ceres/file.cc | 3 +- .../ceres/gradient_checking_cost_function.cc | 4 +- .../libmv/third_party/ceres/internal/ceres/graph.h | 25 +- .../ceres/internal/ceres/graph_algorithms.h | 4 +- .../ceres/iterative_schur_complement_solver.cc | 64 +- .../ceres/iterative_schur_complement_solver.h | 12 +- .../internal/ceres/levenberg_marquardt_strategy.h | 5 +- .../ceres/internal/ceres/line_search.cc | 211 ++++ .../third_party/ceres/internal/ceres/line_search.h | 212 ++++ .../ceres/internal/ceres/line_search_direction.cc | 145 +++ .../ceres/internal/ceres/line_search_direction.h | 70 ++ .../ceres/internal/ceres/line_search_minimizer.cc | 283 ++++++ .../ceres/internal/ceres/line_search_minimizer.h | 77 ++ .../ceres/linear_least_squares_problems.cc | 72 +- .../internal/ceres/linear_least_squares_problems.h | 2 +- .../ceres/internal/ceres/linear_solver.h | 56 +- .../internal/ceres/low_rank_inverse_hessian.cc | 109 +++ .../internal/ceres/low_rank_inverse_hessian.h | 99 ++ .../third_party/ceres/internal/ceres/map_util.h | 1 + .../third_party/ceres/internal/ceres/minimizer.cc | 67 ++ .../third_party/ceres/internal/ceres/minimizer.h | 24 +- .../libmv/third_party/ceres/internal/ceres/mutex.h | 6 +- .../ceres/internal/ceres/parameter_block.h | 61 +- .../internal/ceres/parameter_block_ordering.cc | 122 +++ .../internal/ceres/parameter_block_ordering.h | 78 ++ .../third_party/ceres/internal/ceres/polynomial.cc | 319 ++++++ .../third_party/ceres/internal/ceres/polynomial.h | 134 +++ .../ceres/internal/ceres/polynomial_solver.cc | 184 ---- .../ceres/internal/ceres/polynomial_solver.h | 65 -- .../ceres/internal/ceres/preconditioner.cc | 63 ++ .../ceres/internal/ceres/preconditioner.h | 148 +++ .../third_party/ceres/internal/ceres/problem.cc | 64 +- .../ceres/internal/ceres/problem_impl.cc | 567 ++++++++--- .../ceres/internal/ceres/problem_impl.h | 62 ++ .../ceres/internal/ceres/program_evaluator.h | 28 +- .../ceres/internal/ceres/residual_block.cc | 6 +- .../ceres/internal/ceres/residual_block.h | 21 +- .../ceres/internal/ceres/residual_block_utils.cc | 4 +- .../internal/ceres/schur_complement_solver.cc | 49 +- .../ceres/internal/ceres/schur_complement_solver.h | 6 +- .../ceres/internal/ceres/schur_eliminator_impl.h | 2 +- .../internal/ceres/schur_jacobi_preconditioner.cc | 145 +++ .../internal/ceres/schur_jacobi_preconditioner.h | 110 +++ .../ceres/internal/ceres/schur_ordering.cc | 101 -- .../ceres/internal/ceres/schur_ordering.h | 74 -- .../third_party/ceres/internal/ceres/solver.cc | 331 ++++--- .../ceres/internal/ceres/solver_impl.cc | 1029 ++++++++++++++++---- .../third_party/ceres/internal/ceres/solver_impl.h | 95 +- .../ceres/sparse_normal_cholesky_solver.cc | 36 +- .../internal/ceres/sparse_normal_cholesky_solver.h | 2 +- .../third_party/ceres/internal/ceres/split.cc | 3 +- .../libmv/third_party/ceres/internal/ceres/split.h | 2 +- .../third_party/ceres/internal/ceres/stl_util.h | 16 + .../ceres/internal/ceres/stringprintf.cc | 3 +- .../ceres/internal/ceres/stringprintf.h | 6 +- .../ceres/internal/ceres/suitesparse.cc | 7 +- .../third_party/ceres/internal/ceres/suitesparse.h | 4 +- .../ceres/internal/ceres/triplet_sparse_matrix.cc | 3 +- .../ceres/internal/ceres/trust_region_minimizer.cc | 238 ++--- .../ceres/internal/ceres/trust_region_minimizer.h | 12 +- .../ceres/internal/ceres/trust_region_strategy.cc | 32 + .../ceres/internal/ceres/trust_region_strategy.h | 2 +- .../third_party/ceres/internal/ceres/types.cc | 208 +++- .../third_party/ceres/internal/ceres/visibility.cc | 3 +- .../third_party/ceres/internal/ceres/visibility.h | 2 +- .../ceres/visibility_based_preconditioner.cc | 73 +- .../ceres/visibility_based_preconditioner.h | 79 +- .../third_party/ceres/internal/ceres/wall_time.cc | 96 ++ .../third_party/ceres/internal/ceres/wall_time.h | 88 ++ .../ceres/patches/collections_port.h.mingw.patch | 13 - .../third_party/ceres/patches/msvc_glog_fix.patch | 50 - .../patches/no_previous_declaration_fix.patch | 199 ---- extern/libmv/third_party/ceres/patches/series | 3 - 126 files changed, 9131 insertions(+), 2597 deletions(-) create mode 100644 extern/libmv/third_party/ceres/include/ceres/cost_function_to_functor.h create mode 100644 extern/libmv/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h create mode 100644 extern/libmv/third_party/ceres/include/ceres/gradient_checker.h create mode 100644 extern/libmv/third_party/ceres/include/ceres/internal/numeric_diff.h create mode 100644 extern/libmv/third_party/ceres/include/ceres/internal/variadic_evaluate.h create mode 100644 extern/libmv/third_party/ceres/include/ceres/numeric_diff_functor.h create mode 100644 extern/libmv/third_party/ceres/include/ceres/ordered_groups.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/execution_summary.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/line_search.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/line_search.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/line_search_direction.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/line_search_direction.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/minimizer.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/polynomial.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/polynomial.h delete mode 100644 extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.cc delete mode 100644 extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/preconditioner.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/preconditioner.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h delete mode 100644 extern/libmv/third_party/ceres/internal/ceres/schur_ordering.cc delete mode 100644 extern/libmv/third_party/ceres/internal/ceres/schur_ordering.h create mode 100644 extern/libmv/third_party/ceres/internal/ceres/wall_time.cc create mode 100644 extern/libmv/third_party/ceres/internal/ceres/wall_time.h delete mode 100644 extern/libmv/third_party/ceres/patches/collections_port.h.mingw.patch delete mode 100644 extern/libmv/third_party/ceres/patches/msvc_glog_fix.patch delete mode 100644 extern/libmv/third_party/ceres/patches/no_previous_declaration_fix.patch (limited to 'extern') diff --git a/extern/libmv/third_party/ceres/CMakeLists.txt b/extern/libmv/third_party/ceres/CMakeLists.txt index f0c0a4b269f..5e58c2964ce 100644 --- a/extern/libmv/third_party/ceres/CMakeLists.txt +++ b/extern/libmv/third_party/ceres/CMakeLists.txt @@ -54,6 +54,7 @@ set(SRC internal/ceres/compressed_row_sparse_matrix.cc internal/ceres/conditioned_cost_function.cc internal/ceres/conjugate_gradients_solver.cc + internal/ceres/coordinate_descent_minimizer.cc internal/ceres/corrector.cc internal/ceres/cxsparse.cc internal/ceres/dense_normal_cholesky_solver.cc @@ -71,11 +72,18 @@ set(SRC internal/ceres/linear_least_squares_problems.cc internal/ceres/linear_operator.cc internal/ceres/linear_solver.cc + internal/ceres/line_search.cc + internal/ceres/line_search_direction.cc + internal/ceres/line_search_minimizer.cc internal/ceres/local_parameterization.cc internal/ceres/loss_function.cc + internal/ceres/low_rank_inverse_hessian.cc + internal/ceres/minimizer.cc internal/ceres/normal_prior.cc + internal/ceres/parameter_block_ordering.cc internal/ceres/partitioned_matrix_view.cc - internal/ceres/polynomial_solver.cc + internal/ceres/polynomial.cc + internal/ceres/preconditioner.cc internal/ceres/problem.cc internal/ceres/problem_impl.cc internal/ceres/program.cc @@ -84,7 +92,7 @@ set(SRC internal/ceres/runtime_numeric_diff_cost_function.cc internal/ceres/schur_complement_solver.cc internal/ceres/schur_eliminator.cc - internal/ceres/schur_ordering.cc + internal/ceres/schur_jacobi_preconditioner.cc internal/ceres/scratch_evaluate_preparer.cc internal/ceres/solver.cc internal/ceres/solver_impl.cc @@ -99,26 +107,34 @@ set(SRC internal/ceres/types.cc internal/ceres/visibility_based_preconditioner.cc internal/ceres/visibility.cc + internal/ceres/wall_time.cc include/ceres/autodiff_cost_function.h include/ceres/ceres.h include/ceres/conditioned_cost_function.h include/ceres/cost_function.h + include/ceres/cost_function_to_functor.h include/ceres/crs_matrix.h + include/ceres/dynamic_autodiff_cost_function.h include/ceres/fpclassify.h + include/ceres/gradient_checker.h include/ceres/internal/autodiff.h include/ceres/internal/eigen.h include/ceres/internal/fixed_array.h include/ceres/internal/macros.h include/ceres/internal/manual_constructor.h + include/ceres/internal/numeric_diff.h include/ceres/internal/port.h include/ceres/internal/scoped_ptr.h + include/ceres/internal/variadic_evaluate.h include/ceres/iteration_callback.h include/ceres/jet.h include/ceres/local_parameterization.h include/ceres/loss_function.h include/ceres/normal_prior.h include/ceres/numeric_diff_cost_function.h + include/ceres/numeric_diff_functor.h + include/ceres/ordered_groups.h include/ceres/problem.h include/ceres/rotation.h include/ceres/sized_cost_function.h @@ -141,6 +157,7 @@ set(SRC internal/ceres/compressed_row_jacobian_writer.h internal/ceres/compressed_row_sparse_matrix.h internal/ceres/conjugate_gradients_solver.h + internal/ceres/coordinate_descent_minimizer.h internal/ceres/corrector.h internal/ceres/cxsparse.h internal/ceres/dense_jacobian_writer.h @@ -150,6 +167,7 @@ set(SRC internal/ceres/detect_structure.h internal/ceres/dogleg_strategy.h internal/ceres/evaluator.h + internal/ceres/execution_summary.h internal/ceres/file.h internal/ceres/gradient_checking_cost_function.h internal/ceres/graph_algorithms.h @@ -161,13 +179,19 @@ set(SRC internal/ceres/linear_least_squares_problems.h internal/ceres/linear_operator.h internal/ceres/linear_solver.h + internal/ceres/line_search_direction.h + internal/ceres/line_search.h + internal/ceres/line_search_minimizer.h + internal/ceres/low_rank_inverse_hessian.h internal/ceres/map_util.h internal/ceres/matrix_proto.h internal/ceres/minimizer.h internal/ceres/mutex.h internal/ceres/parameter_block.h + internal/ceres/parameter_block_ordering.h internal/ceres/partitioned_matrix_view.h - internal/ceres/polynomial_solver.h + internal/ceres/polynomial.h + internal/ceres/preconditioner.h internal/ceres/problem_impl.h internal/ceres/program_evaluator.h internal/ceres/program.h @@ -178,7 +202,7 @@ set(SRC internal/ceres/schur_complement_solver.h internal/ceres/schur_eliminator.h internal/ceres/schur_eliminator_impl.h - internal/ceres/schur_ordering.h + internal/ceres/schur_jacobi_preconditioner.h internal/ceres/scratch_evaluate_preparer.h internal/ceres/solver_impl.h internal/ceres/sparse_matrix.h @@ -192,6 +216,7 @@ set(SRC internal/ceres/trust_region_strategy.h internal/ceres/visibility_based_preconditioner.h internal/ceres/visibility.h + internal/ceres/wall_time.h ) #if(FALSE) diff --git a/extern/libmv/third_party/ceres/ChangeLog b/extern/libmv/third_party/ceres/ChangeLog index 8b84328cf98..ebfb771be02 100644 --- a/extern/libmv/third_party/ceres/ChangeLog +++ b/extern/libmv/third_party/ceres/ChangeLog @@ -1,524 +1,572 @@ -commit 552f9f85bba89f00ca307bc18fbda1dff23bd0e4 +commit d2a5195b512164fec286c6a52b40d7766977caa3 Author: Sameer Agarwal -Date: Fri Aug 31 07:27:22 2012 -0700 +Date: Sun Feb 24 15:09:17 2013 -0800 - Various minor bug fixes to the solver logic. + Version history update. - 1. CostFunction returning false is handled better. - If only the cost is being evaluated, it is possible to - use the false value as an infinite value signal/outside - a region of validity. This allows a weak form of constraint - handling. Useful for example in handling infinities. + Change-Id: I477ec05a78ca4cd735a525253c9b6adfa3bddea7 + +commit 2160c5b757c44206c6face6ca62d381f1db7a291 +Author: Sameer Agarwal +Date: Sun Feb 24 14:15:45 2013 -0800 + + Minor release script fixes. - 2. Changed the way how the slop around zero when model_cost - is larger than the current cost. Relative instead of absolute - tolerances are used. The same logic is propagated how the - corresponding clamping of the model_cost is done. + Change-Id: Ifd0a7f4f584c85d4d9574eca46094b372a8d7aff + +commit b53c9667f508c125b8aa833e7a063fa44ef8a98e +Author: Sergey Sharybin +Date: Mon Feb 25 01:14:26 2013 +0600 + + Solve No Previous Prototype GCC warning - 3. Fixed a minor indexing bug in nist.cc. + In some cases there were missing includes of own + header files from implementation files. - 4. Some minor logging fixes to nist.cc to make it more - compatible with the rest of ceres. + In other cases moved function which are only used + within single file into an anonymous namespace. - Together these changes, take the successful solve count from - 41/54 to 46/54 and eliminate all NUMERICAL_FAILURE problems. + Change-Id: I2c6b411bcfbc521e2a5f21265dc8e009a548b1c8 + +commit 267ccc45a3e875bf87832a8ad615be690b4926d3 +Author: Sergey Sharybin +Date: Mon Feb 25 01:04:16 2013 +0600 + + Fix for MinGW build on Windows - Change-Id: If94170ea4731af5b243805c0200963dd31aa94a7 + GG_LONGLONG and GG_ULONGLONG shall use LL and ULL suffixes, + since MinGW is actuall a GCC compiler. + + Solved by checking whether compilation happens with MinGW + or not using standard MinGW's __MINGW32__ and __MINGW64__ + definitions. + + Change-Id: I789b34f6342a56ba42f4b280f7242700022ab7a1 -commit 0b776b5cc9634d3b88d623905b96006f7647ce3e +commit 509f68cfe3fd13b794c4e67ff38c761407c858cf Author: Sameer Agarwal -Date: Thu Aug 30 15:26:17 2012 -0700 +Date: Wed Feb 20 01:39:03 2013 -0800 - Update docs. + Problem::Evaluate implementation. + + 1. Add Problem::Evaluate and tests. + 2. Remove Solver::Summary::initial/final_* + 3. Remove Solver::Options::return_* members. + 4. Various cpplint cleanups. - Change-Id: I69d50bcd37aed3bea2190ca614f023e83172901b + Change-Id: I4266de53489896f72d9c6798c5efde6748d68a47 -commit 2d7176ad7c8fb7238ca8abd6de73415d95877494 -Author: Petter Strandmark -Date: Thu Aug 30 19:51:24 2012 -0700 +commit d4a0bf86d688d1b68e00ff302858de5a4e0d9727 +Author: Keir Mierle +Date: Sun Feb 24 10:35:44 2013 -0800 - max_consecutive_nonmonotonic_steps should be int + Fix threading build on Windows. + + On Windows, including the "windows.h" header defines an enormous number of + symbols; some of which are macros with common names. In particular, "ERROR" and + "min" and "max" get defined. This causes clashes when user code references + these names in a context other than the intended use in windows.h. + + To deal with this, the Microsoft engineers added the ability to control the + definition of these symbols by adding extra defines. In particular, including + windows.h in the following way - Found via Visual Studio warning. + #define NOGDI + #define NOMINMAX - Change-Id: Id2cd7de562dfc8cd35df5d5f5220dd2d7350eb2c + will reduce the number of macros defined. This way they will not conflict with + other uses in Ceres. For example, numeric_limits::max() is impossible + to call without defining NOMINMAX. + + Change-Id: I166f5d3bb6dc0e2e4b2ebf800fb19e49206f7874 -commit 1a89bcc94e88933f89b20427a45bc40cdd23c056 +commit beb4505311011130a7e54632137b0fbb5824cc9b Author: Sameer Agarwal -Date: Thu Aug 30 15:26:17 2012 -0700 +Date: Fri Feb 22 13:37:01 2013 -0800 - Better reporting on the NIST problems. + Minor fixes + + Based on William Rucklidge's review, including + a nasty bug in parameter block removal. - Change-Id: I7cf774ec3242c0612dbe52fc233c3fc6cff3f031 + Change-Id: I3a692e589f600ff560ecae9fa85bb0b76063d403 -commit ea11704857a1e4a735e096896e4d775d83981499 +commit 9a88bd7c4b40e2a1e0cd9b0dc09a3517c467e04e Author: Sameer Agarwal -Date: Wed Aug 29 18:18:48 2012 -0700 +Date: Tue Feb 19 13:09:12 2013 -0800 - Basic harness for testing NIST problems. + Minor bug fixes - Change-Id: I5baaa24dbf0506ceedf4a9be4ed17c84974d71a1 + Change-Id: I94e4521adf76a6c77db954c4a8955168e9d37b55 -commit 98bf14d2b95386c2c4a6c29154637943dae4c36c +commit 956ed7e8f2054623615e6ae3601055d613897f26 Author: Sameer Agarwal -Date: Thu Aug 30 10:26:44 2012 -0700 +Date: Tue Feb 19 07:06:15 2013 -0800 - Miscellaneous fixes. + Various minor fixes. + + 1. Unused variable warnings and fixes. + 2. Minor documentation update. - Change-Id: I521e11f2d20bf24960bbc6b5dab4ec8bb1503d23 + Change-Id: I815588a5806df1030a7c8750f4fb594c503f8998 -commit 1e3cbd9a4442cdd8fda43a7fb452f19dac8c74af -Author: Petter Strandmark -Date: Wed Aug 29 09:39:56 2012 -0700 +commit 3e2c4ef9ad35e94198f4f3367b99fd91e26996a1 +Author: Keir Mierle +Date: Sun Feb 17 12:37:55 2013 -0800 - Caching the symbolic Cholesky factorization when using CXSparse - - Average factorization times for bundle adjustment test problem: - SuiteSparse: 0.2794 s. - CXSparse: 0.4039 s. - CXSparse cached: 0.2399 s. + Add adapters for column/row-major matrices to rotation.h - CXSparse will still be slower, though, because it has to compute - the transpose and J^T * J. + This patch introduces a matrix wrapper (MatrixAdapter) that allows to + transparently pass pointers to row-major or column-major matrices + to the conversion functions. - Change-Id: If9cdaa3dd520bee84b56e5fd4953b56a93db6bde + Change-Id: I7f1683a8722088cffcc542f593ce7eb46fca109b -commit 8b64140878ccd1e183d3715c38942a81fdecefde -Author: Sameer Agarwal -Date: Wed Aug 29 05:41:22 2012 -0700 +commit 04938efe4bedec112083c5ceb227ba004f96bd01 +Author: Keir Mierle +Date: Sun Feb 17 12:37:55 2013 -0800 - Documentation update + Add support for removing parameter and residual blocks. - Change-Id: I271a0422e7f6f42bcfd1dc6b5dc10c7a18f6a179 - -commit a5353acd85a9fd19370b3d74035d87b0f0bac230 -Author: Petter Strandmark -Date: Tue Aug 28 18:16:41 2012 -0700 - - Adding gflags include to test_util.cc + This adds support for removing parameter and residual blocks. + There are two modes of operation: in the first, removals of + paremeter blocks are expensive, since each remove requires + scanning all residual blocks to find ones that depend on the + removed parameter. In the other, extra memory is sacrificed to + maintain a list of the residuals a parameter block depends on, + removing the need to scan. In both cases, removing residual blocks + is fast. - test_util seems to need gflags. + As a caveat, any removals destroys the ordering of the parameters, + so the residuals or jacobian returned from Solver::Solve() is + meaningless. There is some debate on the best way to handle this; + the details remain for a future change. - Change-Id: I0c4757960f8ac69ad599c138aea58e3c88a4ea28 - -commit 87ca1b2ba28ec512752bbcf5fc994ce1434eb765 -Author: Petter Strandmark -Date: Tue Aug 28 18:05:20 2012 -0700 - - Changing random.h to use cstdlib for Windows compability. + This also adds some overhead, even in the case that fast removals + are not requested: - As discussed with Sameer today. + - 1 int32 to each residual, to track its position in the program. + - 1 pointer to each parameter, to store the dependent residuals. - Change-Id: If3d0284830c6591c71cc77b8400cafb45c0da61f + Change-Id: I71dcac8656679329a15ee7fc12c0df07030c12af -commit aeb00a07323808a0a1816e733ad18a87d5109ea3 -Author: Petter Strandmark -Date: Mon Aug 27 22:22:57 2012 -0700 +commit fa21df8cd969bb257b87c9ef7c0147d8d5ea8725 +Author: Sameer Agarwal +Date: Mon Feb 18 08:48:52 2013 -0800 - Removing gomp for Visual Studio + Add script for building documentation. + + Update make_release - Linking currently fails in Visual Studio due to a missing library - "gomp.lib". This is not needed in Visual Studio. OpenMP works - without it. + Minor documentation fixes. - Change-Id: I39e204a8dd4f1b7425df7d4b222d86a8bb961432 + Change-Id: I1248ec3f58be66b5929aee6f2aa392c15d53ed83 -commit 6f362464ba99b800494d2f15c27768a342ddaa68 -Author: Markus Moll -Date: Tue Aug 28 01:03:38 2012 +0200 +commit 290b975d1d4eba44205bbeb0fa6b3ce8a6fa4a0c +Author: Sameer Agarwal +Date: Sun Feb 17 16:50:37 2013 -0800 - Add some tests for DoglegStrategy. + Preconditioner refactoring. - Not necessarily a complete set. + 1. Added a Preconditioner interface. + 2. SCHUR_JACOBI is now its own class and is independent of + SuiteSparse. - Change-Id: I14eb3a38c6fe976c8212f3934655411b6d1e0aa4 + Change-Id: Id912ab19cf3736e61d1b90ddaf5bfba33e877ec4 -commit 122cf836a6dc9726489ce2fbecc6143bddc1caaf +commit d010de543530001fa917501a13ba02879c8ea52f Author: Sameer Agarwal -Date: Fri Aug 24 16:28:27 2012 -0700 +Date: Fri Feb 15 14:26:56 2013 -0800 - Documentation update. + Solver::Summary::FullReport() supports line search now. - Change-Id: I0a3c5ae4bc981a8f5bdd5a8905f923dc5f09a024 + Change-Id: Ib08d300198b85d9732cfb5785af4235ca4bd5226 -commit 69081719f73da8de2935774a42d237837a91952a -Author: Keir Mierle -Date: Mon Aug 27 13:28:56 2012 -0700 +commit fbbea464d1c9575d8224220d3e61f92d93fe9739 +Author: Sameer Agarwal +Date: Fri Feb 15 11:25:03 2013 -0800 - Remove unnecessary overload for hash<> + Update documentation. - The overload for pointers in hash tables was applied in normal - usage of schur_ordering.cc. However, the tests did not include the - overload since they only included collections_port.h. As a result, - the routines in schur_ordering.cc were using a different hash - function than that inside the tests. - - The fix is to remove the specialization. If this breaks one of the - compiler configurations, we will find a workaround at that time. - - Change-Id: Idbf60415d5e2aec0c865b514ad0c577d21b91405 + Change-Id: Idb03741fab9facbbbda85d5a82723f0b4c1c6c60 -commit 1762420b6ed76b1c4d30b913b2cac1927b666534 +commit 8e1f83c4c457fb7238eb342eab744c5570b73c4d Author: Sameer Agarwal -Date: Wed Aug 22 10:01:31 2012 -0700 +Date: Fri Feb 15 08:35:40 2013 -0800 - Update changelog. + Speed up Problem construction and destruction. - Change-Id: Idf5af69d5a9dbe35f58e30a8afcbfcd29bb7ebfe + Change-Id: I3147b0b60eedf40f8453d5a39ff04a572c445a2f -commit 976ab7aca908309b8282cb40bc080ca859136854 -Author: Keir Mierle -Date: Thu Aug 23 18:21:36 2012 -0700 +commit efb47f39c31f0ef1bb9c015c8c0d114153df6379 +Author: Sameer Agarwal +Date: Thu Feb 14 19:44:11 2013 -0800 - Remove Google-era vestigial unit test. + Documentation update - Change-Id: Ia7a295a5c759a17c1675a3055d287d3e40e9e0fe + Change-Id: I0fec43bff4fe0ea6cd2d2a8b34dac2330a517da0 -commit 6ad6257de0e2152ac5e77dc003758de45187d6ea -Author: Keir Mierle -Date: Wed Aug 22 11:10:31 2012 -0700 +commit be418a336cae5672111e0f6989e6d8d6c1fa24a6 +Author: Markus Moll +Date: Fri Feb 15 17:19:28 2013 +0100 - Add a workaround for an Android NDK compiler bug. - - On certain NDK build configurations, one of the innermost - parts of the Schur eliminator would get compiled - incorrectly. The compiler changed a -= to a +=. + Fix evaluation of initial cost and corresponding test - The normal Ceres unit tests caught the problem; however, - since it is not possible to build the tests with the NDK - (only with the standalone toolchain) this was difficult to - track down. Finding the issue involved pasting the schur - eliminator unit test inside of solver_impl.cc and other such - hacks. + Commit f102a68e411d11b4864e17b69a2d781e9c2692ad seems to have introduced + a bug in both solver_impl.cc and solver_impl_test.cc + solver_impl_test showed 3 errors, where two were due to ceres NOT + failing when the test expected that, and one was due to the initial cost + being wrong (-1 instead of 0.5) + Ceres now does not attempt to evaluate the initial cost if + options.return_initial_xxx is not set. It therefore did not fail in + the tests. + It also seems that the CERES_EVALUATE macro erroneously always sets + final_cost, even when called with 'initial' as argument. - Change-Id: Ie91bb545d74fe39f0c8cbd1a6eb69ee4d8b25fb2 + Change-Id: Ia3c3eeb476e7023a3f80b201124010d6c67e9824 -commit aecb2dc92b4aa7f3bf77a1ac918e62953602392b +commit 974513a41ff1ddc671d3dc6aa09ce708bbe447da Author: Sameer Agarwal -Date: Wed Aug 22 10:08:17 2012 -0700 +Date: Tue Feb 12 14:22:40 2013 -0800 - Fix relative path bug in bibtex call. + Bug fix in DynamicAutoDiffCostFunction + + Add handling of constant parameter blocks. - Change-Id: I0d31786564320a6831259bcdf4c75a6b665c43ad + Change-Id: I8b2ea79f47e190604fc4bed27705798240689f71 -commit 1e2892009e591804df6286caebd5c960e7e3b099 -Author: Sameer Agarwal -Date: Tue Aug 21 18:00:54 2012 -0700 +commit 3130b3cea4028c71d9ae18b7465d7627f29fef7d +Author: Keir Mierle +Date: Mon Feb 11 19:39:29 2013 -0800 - Update Summary::FullReport to report dogleg type. + Add support for dynamic autodiff - Change-Id: I0b4be8d7486c1c4b36b299693b3fe8b0d3426537 + Change-Id: I17d573696172ab691a9653db99a620e4bc1bd0d0 -commit 295ade1122a86b83e1ea605d5ca394f315874717 +commit c58e6dc3ea550302c8151003b17e9bc2a1acc316 Author: Sameer Agarwal -Date: Wed Aug 22 06:51:22 2012 -0700 +Date: Mon Feb 11 16:41:06 2013 -0800 - Fix Eigen3 Row/Column Major storage issue. - - Eigen3 does not allow column vectors to be stored in row-major - format. NumericDiffCostFunction by default stores its Jacobian - matrices in row-major format. This works fine if the residual - contains more than one variable. But if the residual block - depends on one variable and has more than one residuals, the - resulting Jacobian matrix is a column matrix in row-major format - resulting in a compile time error. + More refined event logging in solver_impl.cc - The fix is to check the template parameters and switch to column-major - storage as needed. - - Thanks to Lena Gieseke for reporting this. - - Change-Id: Icc51c5b38e1f3609e0e1ecb3c4e4a02aecd72c3b + Change-Id: Ie3061c921c006d2600d16185c690f52ccf816f68 -commit 9ad27e8e9fb1bbd2054e2f6ae37623e01428f1c0 -Author: Arnaud Gelas -Date: Tue Aug 21 09:56:30 2012 +0200 +commit f102a68e411d11b4864e17b69a2d781e9c2692ad +Author: Sameer Agarwal +Date: Mon Feb 11 15:08:40 2013 -0800 - Add one uninstall target to remove all installed files + Remove extraneous initial and final evals. - Change-Id: Ifcf89a6c27b25f28403d95a50e29c093a525298f + Change-Id: I80ed87435f399cbf452c68be7ea1e7139696aa4a -commit 0c3a748ee49e04fe334f8f5a433649d18003d550 -Author: Markus Moll -Date: Tue Aug 21 14:44:59 2012 +0200 +commit 0593747ee09e21a9c0a2b604d51e21a6cdd21315 +Author: Sameer Agarwal +Date: Mon Feb 11 13:57:12 2013 -0800 - Allow equal lower and upper bound for diagonal scaling. + Fix a memory leak in cxsparse.cc - This way, setting the lower and upper bound both to 1.0, one can disable - the automatic trust region scaling. + Thanks to Alexander Mordvintsev for reporting it. - Change-Id: Ifa317a6911b813a89c1cf7fdfde25af603705319 + Change-Id: Ia872be42ce80209e46722fc16a928496cf97e256 -commit 3d644b76adefac6475b91dc53c3ae5e01c4f4d66 -Author: Arnaud Gelas -Date: Thu Aug 16 17:33:21 2012 +0200 +commit 0abfb8f46f534b05413bb4d64b960d6fd0a9befb +Author: Sameer Agarwal +Date: Mon Feb 11 13:40:04 2013 -0800 - Install headers, libraries and pdf + Delete the tex documentation. - Headers are installed in ${CMAKE_INSTALL_PREFIX}/include/ceres - Libraries are installed in ${CMAKE_INSTALL_PREFIX}/lib - pdf is installed in ${CMAKE_INSTALL_PREFIX}/share/ceres/docs - - Change-Id: Ic175f2c2f5fa86820a1e8c64c2ed171f4a302a68 + Change-Id: I15c78a8b33c5fd94941238814ac023a8fb251a20 -commit d2fb5adea4d8c2aeb43c4289c6976798a54d3cf1 -Author: Arnaud Gelas -Date: Fri Aug 17 10:11:02 2012 +0200 +commit 085cd4a6641c404334d17e5ea38f9e5b68a06ba7 +Author: Sameer Agarwal +Date: Wed Feb 6 14:31:07 2013 -0800 - Configure gerrit hook at CMake time + Rewrite of the tutorial. - If the source directory is a clone, at CMake time the commit-msg hook gets - downloaded and installed in the right location. + 1. Quicker starting point. + 2. Better discussion of derivatives. + 3. Better hyperlinking to code and class documentation. + 4. New robust estimation example. + 5. Better naming of example code. + 6. Removed dependency on gflags in all the core examples covered + in the tutorial. - Change-Id: I5fee17d050ca22d8b92a49fdcc2a1cd6659f209b + Change-Id: Ibf3c7fe946fa2b4d22f8916a9366df267d34ca26 -commit 73166098fc4b1072adc30321c666188a3909c43c -Author: Arnaud Gelas -Date: Mon Aug 20 15:40:41 2012 +0200 +commit c0fdc9753909fc37fed2cb5e0fcc02fc65789d68 +Author: Sameer Agarwal +Date: Wed Feb 6 14:31:07 2013 -0800 - Add one CMake option to build the examples. + Update nist.cc to better evaluate results. - Currently the examples are always built. For external projects, it is useful - not to compile the examples. + Ceres beats Minpack and HBN handily. - Change-Id: I41d3bde19c7e742818e60f78222d39c43992ca8b + Change-Id: I7df8a47b753202ed0b53ab128ce48466bf9f8083 -commit 86d4f1ba41ef14eb1b6b61a7936af83387b35eb2 -Author: Keir Mierle -Date: Mon Aug 20 11:52:04 2012 -0700 +commit d91b671798125fd4889914d92a29cf0f7a5fef21 +Author: Sameer Agarwal +Date: Wed Feb 6 01:08:40 2013 -0800 - Add missing return statement. + More small changes + More small changes to the docs. - Change-Id: I5eaf718318e27040e3c97e32ee46cf0a11176a37 - -commit 51eb229da34187a4e8ce73ed9cc0e731998bb2be -Author: Keir Mierle -Date: Mon Aug 20 11:46:12 2012 -0700 - - Add Program::ToString() to aid debugging. + 1. Better landing page. + 2. Minor tweaks to the side bar. + 3. Reference to more example code. + 4. Local MathJax references. - Change-Id: I0ab37ed2fe0947ca87a152919d4e7dc9b56dedc6 + Change-Id: I39b9436dc2803732a875bbbee7f15802c4934031 -commit bcc7100635e2047dc2b77df19a4ded8a6ab4d4b9 -Author: Keir Mierle -Date: Mon Aug 20 11:45:04 2012 -0700 +commit 42a84b87fa5cc34551244a3b2b6a3e1f13a29514 +Author: Sameer Agarwal +Date: Fri Feb 1 12:22:53 2013 -0800 - Ignore minted.sty. + Expand reporting of timing information. - Change-Id: I2467a6f801812b9007b51bf14b00757f026e4322 + 1. Add an ExecutionSummary object to record execution + information about Ceres objects. + 2. Add an EventLogger object to log events in a function call. + 3. Add a ScopedExecutionTimer object to log times in ExecutionSummary. + 4. Instrument ProgramEvaluator and all the linear solvers + to report their timing statistics. + 5. Connect the timing statistics to Summary::FullReport. + 6. Add high precision timer on unix systems using + gettimeofday() call. + 7. Various minor clean ups all around. + + Change-Id: I5e09804b730b09535484124be7dbc1c58eccd1d4 -commit 9705a736dd3d6fbead0d8a6ff77102c69bbcdc08 -Author: Keir Mierle -Date: Mon Aug 20 11:24:05 2012 -0700 +commit 08c891fcb6ea1bf66e6d4619273765a644605dfc +Author: Sameer Agarwal +Date: Mon Feb 4 20:18:58 2013 -0800 - Add ParameterBlock::ToString() to aid debugging. + Various small changes. - Change-Id: Id3f5cb27b855c536dd65a986f345bd8eb2799dfa + 1. Compact build instructions. + 2. Lots of small edits by Simon Fuhrmann. + + Change-Id: I8c0c67922021041dcf7f4ecdb6c6e6dd2e2fd7e5 -commit 0c714a70e6123ceb68e5cfcd3cfbee0d09deb1db +commit e2e857ad6be322e9cf750d4b11ccf10800e57d96 Author: Sameer Agarwal -Date: Mon Aug 20 11:18:16 2012 -0700 +Date: Mon Feb 4 19:40:45 2013 -0800 - Fix blanks before private in loss_function.h + Sidebar has global table of contents. - Change-Id: I068bed6431bc7c9b7958af391655df61499000b2 + Change-Id: I7fe9053868a4660b0db8d7607ee618fc30ddaefd -commit 51cf7cbe3bac45c6807c2703a2fc3175d76a1b47 -Author: Markus Moll -Date: Mon Aug 20 20:10:20 2012 +0200 +commit b9182147d96f865673c2756ced4cbb127ca082a3 +Author: Sameer Agarwal +Date: Mon Feb 4 17:55:25 2013 -0800 - Add the two-dimensional subspace search to DoglegStrategy + Change the theme to be closer to ReadTheDocs.org - Change-Id: I5163744c100cdf07dd93343d0734ffe0e80364f3 + Change-Id: I61a76f5b5e5c292b54fdf51b66940ce80bd1cd5f -commit ad1f7b772e559a911ac3a3b078b0aee1836fe785 +commit 3d87b72c895835bbfc10965d50dc96608632114d Author: Sameer Agarwal -Date: Mon Aug 20 11:10:34 2012 -0700 +Date: Sat Feb 2 00:49:31 2013 -0800 - Add ArcTanLoss, TolerantLoss and ComposedLossFunction. + Convert documentation from LaTeX to Sphinx. - Based on work by James Roseborough. + A live version of the doc can be found at - Change-Id: Idc4e0b099028f67702bfc7fe3e43dbd96b6f9256 + http://homes.cs.washington.edu/~sagarwal/ceres-solver/ + + As it stands, the documentation has better hyperlinking + and coverage than the latex documentation now. + + Change-Id: I7ede3aa83b9b9ef25104caf331e5727b4f5beae5 -commit 05292bf8fc5208b86b4a13544615b584f6efa936 +commit 71c8058478311ff9b3087360827e048dec5dd69a Author: Sameer Agarwal -Date: Mon Aug 20 07:40:45 2012 -0700 +Date: Thu Jan 31 17:33:01 2013 -0800 - Add a TrustRegionStrategy::Summary object. + Remove ExecutionSummary from Evaluator and LinearSolver - Change-Id: I7caee35a3408ee4a0ec16ba407410d822929340d + Change-Id: If4dbaf516a8b14e0a79e1a2116ce66a99ed4a592 -commit b12b906c4d21c3949f0dce62c4c0d083c8edecf1 -Author: Arnaud Gelas -Date: Wed Aug 15 16:27:38 2012 +0200 +commit fa1c31eee33051d6483bc90fa7b66c3664b23bf3 +Author: Sameer Agarwal +Date: Tue Jan 29 17:24:54 2013 -0800 - Add one option to generate the PDF from CMake at build time + Correct the documentation for crs_matrix.h - Make sure pygmentize is installed + Thanks to Joydeep Biswas for reporting this. - Change-Id: I068ba45c33a8e96acc906a464b12d10d58b3e231 + Change-Id: Iae5fc2274644aab40f2f922a671f65da15ae71fc -commit b9f15a59361c609ffc4a328aea9be3d265b5da81 +commit bdd87c03ed1cbac62990bf79aa6faed0a132bba9 Author: Sameer Agarwal -Date: Sat Aug 18 13:06:19 2012 -0700 +Date: Tue Jan 29 16:24:31 2013 -0800 - Add a dense Cholesky factorization based linear solver. + Add an ExecutionSummary object that the Evaluator and LinearSolver can use to + report execution statistics of all kinds. - For problems with a small number of variables, but a large - number of residuals, it is sometimes beneficial to use the - Cholesky factorization on the normal equations, instead of - the dense QR factorization of the Jacobian, even though it - is numerically the better thing to do. + Currently a single map which maps arbitrary strings to doubles is supported, + which allows for precise timing information to be communicated. - Change-Id: I3506b006195754018deec964e6e190b7e8c9ac8f + Change-Id: Ibd930aca5c9e6cae89bcfeffe9b13e2887644881 -commit b3fa009435acf476cd373052e62988f6437970b1 -Author: Arnaud Gelas -Date: Fri Aug 17 10:31:41 2012 +0200 +commit a2fd9ca8beb5aa11fcc5d2b32e23f161edc93d28 +Author: Sameer Agarwal +Date: Tue Jan 29 16:02:41 2013 -0800 - Set CMAKE_*_OUTPUT_DIRECTORY - - Gather - * all executables in ${CMAKE_BINARY_DIR}/bin - * all libraries (static and dynamic) in ${CMAKE_BINARY_DIR}/lib + Fix Android.mk - Change-Id: Ibc2fa1adfb6f0aea65d66d570259b79546bf3b07 + Change-Id: I1093c2731283890d1f3792bf8e6741f448f1465d -commit 1b8a4d5d11671ed83cf6077e363dd95333f08ef8 +commit 977be7cac37316524038fa0168cc5994a5654acd Author: Sameer Agarwal -Date: Fri Aug 17 16:49:11 2012 -0700 +Date: Sat Jan 26 16:01:54 2013 -0800 - Fix a minor bug in detect_structure logging. + Add support for reporting linear solver and inner iteration + orderings. - Change-Id: I117f7745e4c67595b3ff9244cde82b5b5b34ee4b + Change-Id: I0588a4285e0925ce689e47bd48ddcc61ce596a1f -commit 31c1e784ab2cb9294c6e05414cf06aae2b3766de -Author: Keir Mierle -Date: Fri Aug 17 16:16:32 2012 -0700 +commit 146b9acb4d5570da311fedb5222ad65fe12f233c +Author: Sameer Agarwal +Date: Mon Jan 21 16:16:58 2013 -0800 - Minor cleanups. + Update include/ceres.h to export headers. + Update the ABI version. - Change-Id: Ida4866997deeaa1bc2cebd6b69313a05ac82e457 + Change-Id: I5c1c4f110cddc816bbb5a737634f55b4cbea98e1 -commit e83f7879a8b21c6976e116958caf35bcdcf41cb0 +commit e837aeaf9e63936d745519fa53c726a2ca9d5822 Author: Sameer Agarwal -Date: Fri Aug 17 15:34:42 2012 -0700 +Date: Mon Jan 21 13:05:01 2013 -0800 - Fix SuiteSparse3 UFConfig.h detection really. + Documentation update. - Change-Id: Id187102e755b7d778dff4363f22f9a4697ed12dd + Change-Id: Ica8681f4bb58c60349d0dae453c652f2522eebf6 -commit 96f25dc57658d296ee6b6633818b4f1e51d7d587 +commit 2f0d7249ccedac8183e6e5a9cb45ca7c51bb6b41 Author: Sameer Agarwal -Date: Fri Aug 17 15:34:42 2012 -0700 +Date: Fri Jan 18 13:11:32 2013 -0800 - Fix SuiteSparse3 UFConfig.h detection. + NumericDiffFunctor. - Change-Id: Ia59aefdb0ad7f713f76ed79692f2db4fa2821e5b - -commit c497bd6cd9aa944f518aa491d3bc645851ff9594 -Author: Markus Moll -Date: Fri Aug 17 14:40:13 2012 +0200 - - Add UFconfig and/or SuiteSparse_config test to CMakeLists.txt + A wrapper class that takes a variadic functor evaluating a + function, numerically differentiates it and makes it available as a + templated functor so that it can be easily used as part of Ceres' + automatic differentiation framework. - SuiteSparse 4 requires linking to libsuitesparseconfig.a. - Both SuiteSparse 3 and SuiteSparse 4 require an additional header - (either UFconfig.h or SuiteSparse_config.h) that is not found if it is - in a separate path. Therefore, add explicit checks. + The tests for NumericDiffCostFunction and NumericDiffFunctor have + a lot of stuff that is common, so refactor them to reduce code. - Change-Id: I699902b5db4f1b7f17134b5a54f9aa681445e294 + Change-Id: I83b01e58b05e575fb2530d15cbd611928298646a -commit 383c04f4236d92801c7c674892814362dedf7ad6 +commit 2fc0ed6143ad499d6dc82d621ff5ec69170beb52 Author: Sameer Agarwal -Date: Fri Aug 17 10:14:04 2012 -0700 +Date: Tue Jan 15 11:34:10 2013 -0800 - Fix QuaternionToAngleAxis to ensure rotations are between -pi and pi. + Change NumericDiffCostFunction to accept variadic functors. + + The interface for NumericDiffCostFunction and AutoDiffCostFunction + are not comparable. They both accept variadic functors. - Thanks to Guoxuan Zhang for reporting this. + The change is backward compatible, as it still supports numeric + differentiation of CostFunction objects. - Change-Id: I2831ca3a04d5dc6467849c290461adbe23faaea3 + Some refactoring of documentation and code in auto_diff_cost_function + and its relatives was also done to make things consistent. + + Change-Id: Ib5f230a1d4a85738eb187803b9c1cd7166bb3b92 -commit dd2b17d7dd9750801ba4720bdece2062e59b7ae3 +commit 9c5acce674e3ec1ba08509123ff519f106cc4348 Author: Sameer Agarwal -Date: Thu Aug 16 19:34:57 2012 -0700 +Date: Sun Jan 13 22:14:12 2013 -0800 - CERES_DONT_HAVE_PROTOCOL_BUFFERS -> CERES_NO_PROTOCOL_BUFFERS. + Add CostFunctionToFunctor. + + CostFunctionToFunctor wraps a CostFunction, and makes it available + as a templated functor that can be called from other templated + functors. This is useful for when one wants to mix automatic, + numeric and analytic differentiated functions. + + Also a bug fix in autodiff.h - Change-Id: I6c9f50e4c006faf4e75a8f417455db18357f3187 + Change-Id: If8ba281a89fda976ef2ce10a5844a74c4ac7b84a -commit 8b4cb7aa2c74a0da62c638b2023566aa242af995 +commit c89ea4b9de588e2e2e82c54cd1c30cddb11454c5 Author: Sameer Agarwal -Date: Thu Aug 16 19:26:55 2012 -0700 +Date: Wed Jan 9 16:09:35 2013 -0800 - Fix sparse linear algebra library logging in Summary::FullReport. + Minor corrections based on Jim Roseborough's comments - Change-Id: Id2c902dc86c00954fde7749c7b4a67dd94215a31 + Change-Id: I4a8c7a454ddf038a3ed2567c101f9aee582044bf -commit 47d26bcd3b38b5ff53b34768c33b499d47b26bd0 -Author: Markus Moll -Date: Thu Aug 16 00:23:38 2012 +0200 +commit 00c8a061929b912bda3cfd4615fb8688c246c969 +Author: Keir Mierle +Date: Sat Dec 1 13:22:59 2012 -0800 - Do not implicitly negate the step in the TrustRegionMinimizer. - - In the TrustRegionMinimizer, the step is currently implicitly negated. - This is done so that the linearized residual is |r - J*step|^2, which - corresponds to J*step = r, so neither J nor r have to be modified. - However, it leads to the rather unintuitive situation that the strategy - returns a step in positive gradient direction, which you would expect to - increase the function value. One way is to rename the "step" parameter in - the strategy to "negative_step" and document it. - This patch instead moves the negation inside the strategy, just around - the linear solver call, so that it is done in a local context and easier - to document. + Fix bug in DenseSparseMatrix::ToDenseMatrix(). - Change-Id: Idb258149a01f61c64e22128ea221c5a30cd89c89 + Change-Id: I74a1a03149d74fbc4268ec3ce9d20e09746a7227 -commit 51da590c8457e6664f76fe9813425a0c71351497 -Author: Markus Moll -Date: Fri Aug 17 12:56:09 2012 +0200 +commit bcac4de5b75cae210c5557c81239222176d2709a +Author: Sameer Agarwal +Date: Fri Nov 30 23:11:26 2012 -0800 - Remove tmp file + Speedup corrector.cc + + Add a specialization for the common case where the residual block + outputs exactly one residual. - Change-Id: I07496fafae7b0c5c12cc26ae336e0db3b5592735 + The matrix routines used by Corrector can be then specialized to + a scalar and be made considerably faster. + + For denoising upto 400% speedup is observed. + + Change-Id: I8e3f24b8ba41caa8e62ad97c5f5e96ab6ea47150 -commit 7006a1f2b1701b8d89b8d1525fc0101943802221 +commit 9883fc396b2913fbc597afa795c39d365229c299 Author: Sameer Agarwal -Date: Thu Aug 16 18:04:22 2012 -0700 +Date: Fri Nov 30 12:32:43 2012 -0800 - Correct example code in Powell's function example. + Refactoring of the LineSearchMinimizer. - Thanks to Petter Strandmark for pointing this out. + 1. New LineSearchDirection interface, factory and instances. + 2. Cleanup of LineSearchMinimizer to use the State and Direction objects. + 3. LBFGS -> LowRankInverseHessian. + 4. Refactoring of the RunCallbacks function and share it across + LineSearchMinimizer and TrustRegionMinimizer. - Change-Id: I967632235dccdb481396e94904bb911c9a1efe1e + Change-Id: I19354afc6f5d6567b28918710c2012dc30ef8f32 -commit 57a44b27bc6fc95b4e70fdc25c25c9925a2072a0 -Author: Keir Mierle -Date: Thu Aug 16 17:04:50 2012 -0700 +commit 2293cb5bc96a5b317ed4ca52aa3494cadecbc07c +Author: Sameer Agarwal +Date: Thu Nov 29 16:00:18 2012 -0800 - Remove unnecessary flags in NDK build. + Add missing documentation to solver.h - Change-Id: Ib5b4d0b7f2d898671252734978c789b8171d96a8 + Change-Id: I86e7c4f1f6cc1e15d5eb2cf23e73c32d94d458c1 -commit f21bee247251a8b2e836c215a84c4668c31d75cd -Author: Keir Mierle -Date: Thu Aug 16 16:27:10 2012 -0700 +commit aed99615c017839df09c98f518dcc0a59a9819ec +Author: Sameer Agarwal +Date: Thu Nov 29 10:33:19 2012 -0800 - Fix for fpclassify.h NDK porting work. + Expose lbfgs rank in solver.h - Change-Id: I69df1b4caf2941ed96a53e35e43ec54073f84f59 + Change-Id: Ibc184b1a2f94a4057fa6569d539ca3a55d6d6098 -commit 8ceb02cb75b66602de44a35e413225386cb21c27 -Author: Keir Mierle -Date: Thu Aug 16 14:23:47 2012 -0700 +commit 1afd498f50ef520868c18a0f26b55409d8471ceb +Author: Sameer Agarwal +Date: Thu Nov 29 10:28:11 2012 -0800 - Add Android NDK build files. + String to and from enum conversion routines. + + Update types.h/cc with stringication and unstringication + routines for the newly introduced enums. - This adds a Android.mk build that builds a Ceres static library - suitable for embetting in larger Android applications. This is - useful when needing to build Ceres without GPL'd components, since - the standalone toolchain (needed for the CMake Android build) does - not work with STLPort. + Change-Id: I0fe2842b5b1c75ba351f4ab87ec9fa60af2f9ed2 + +commit 3e8d192f2871bcf6d5f248c119c8a6eef19186d3 +Author: Sameer Agarwal +Date: Wed Nov 28 17:20:22 2012 -0800 + + Add a rough implementation of LBFGS. - Change-Id: I8d857237f6f82658741017d161b2e31d9a20e5a7 + Change-Id: I2bc816adfe0c02773a23035ea31de3cddc1322a4 diff --git a/extern/libmv/third_party/ceres/bundle.sh b/extern/libmv/third_party/ceres/bundle.sh index 76630bc0626..b2c8330ec3e 100755 --- a/extern/libmv/third_party/ceres/bundle.sh +++ b/extern/libmv/third_party/ceres/bundle.sh @@ -9,7 +9,8 @@ fi repo="https://ceres-solver.googlesource.com/ceres-solver" branch="master" -tag="1.3.0" +#tag="1.4.0" +tag="" tmp=`mktemp -d` checkout="$tmp/ceres" @@ -120,7 +121,7 @@ set(INC include internal ../gflags - ../.. + ../../ ) set(INC_SYS diff --git a/extern/libmv/third_party/ceres/files.txt b/extern/libmv/third_party/ceres/files.txt index 55083572977..8f4b7b97b50 100644 --- a/extern/libmv/third_party/ceres/files.txt +++ b/extern/libmv/third_party/ceres/files.txt @@ -2,21 +2,28 @@ include/ceres/autodiff_cost_function.h include/ceres/ceres.h include/ceres/conditioned_cost_function.h include/ceres/cost_function.h +include/ceres/cost_function_to_functor.h include/ceres/crs_matrix.h +include/ceres/dynamic_autodiff_cost_function.h include/ceres/fpclassify.h +include/ceres/gradient_checker.h include/ceres/internal/autodiff.h include/ceres/internal/eigen.h include/ceres/internal/fixed_array.h include/ceres/internal/macros.h include/ceres/internal/manual_constructor.h +include/ceres/internal/numeric_diff.h include/ceres/internal/port.h include/ceres/internal/scoped_ptr.h +include/ceres/internal/variadic_evaluate.h include/ceres/iteration_callback.h include/ceres/jet.h include/ceres/local_parameterization.h include/ceres/loss_function.h include/ceres/normal_prior.h include/ceres/numeric_diff_cost_function.h +include/ceres/numeric_diff_functor.h +include/ceres/ordered_groups.h include/ceres/problem.h include/ceres/rotation.h include/ceres/sized_cost_function.h @@ -54,6 +61,8 @@ internal/ceres/compressed_row_sparse_matrix.h internal/ceres/conditioned_cost_function.cc internal/ceres/conjugate_gradients_solver.cc internal/ceres/conjugate_gradients_solver.h +internal/ceres/coordinate_descent_minimizer.cc +internal/ceres/coordinate_descent_minimizer.h internal/ceres/corrector.cc internal/ceres/corrector.h internal/ceres/cxsparse.cc @@ -71,6 +80,7 @@ internal/ceres/dogleg_strategy.cc internal/ceres/dogleg_strategy.h internal/ceres/evaluator.cc internal/ceres/evaluator.h +internal/ceres/execution_summary.h internal/ceres/file.cc internal/ceres/file.h internal/ceres/generated/schur_eliminator_2_2_2.cc @@ -107,18 +117,31 @@ internal/ceres/linear_operator.cc internal/ceres/linear_operator.h internal/ceres/linear_solver.cc internal/ceres/linear_solver.h +internal/ceres/line_search.cc +internal/ceres/line_search_direction.cc +internal/ceres/line_search_direction.h +internal/ceres/line_search.h +internal/ceres/line_search_minimizer.cc +internal/ceres/line_search_minimizer.h internal/ceres/local_parameterization.cc internal/ceres/loss_function.cc +internal/ceres/low_rank_inverse_hessian.cc +internal/ceres/low_rank_inverse_hessian.h internal/ceres/map_util.h internal/ceres/matrix_proto.h +internal/ceres/minimizer.cc internal/ceres/minimizer.h internal/ceres/mutex.h internal/ceres/normal_prior.cc internal/ceres/parameter_block.h +internal/ceres/parameter_block_ordering.cc +internal/ceres/parameter_block_ordering.h internal/ceres/partitioned_matrix_view.cc internal/ceres/partitioned_matrix_view.h -internal/ceres/polynomial_solver.cc -internal/ceres/polynomial_solver.h +internal/ceres/polynomial.cc +internal/ceres/polynomial.h +internal/ceres/preconditioner.cc +internal/ceres/preconditioner.h internal/ceres/problem.cc internal/ceres/problem_impl.cc internal/ceres/problem_impl.h @@ -137,8 +160,8 @@ internal/ceres/schur_complement_solver.h internal/ceres/schur_eliminator.cc internal/ceres/schur_eliminator.h internal/ceres/schur_eliminator_impl.h -internal/ceres/schur_ordering.cc -internal/ceres/schur_ordering.h +internal/ceres/schur_jacobi_preconditioner.cc +internal/ceres/schur_jacobi_preconditioner.h internal/ceres/scratch_evaluate_preparer.cc internal/ceres/scratch_evaluate_preparer.h internal/ceres/solver.cc @@ -166,3 +189,5 @@ internal/ceres/visibility_based_preconditioner.cc internal/ceres/visibility_based_preconditioner.h internal/ceres/visibility.cc internal/ceres/visibility.h +internal/ceres/wall_time.cc +internal/ceres/wall_time.h diff --git a/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h b/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h index da9ee2c7993..e758d3a2bd5 100644 --- a/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h +++ b/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h @@ -28,10 +28,10 @@ // // Author: sameeragarwal@google.com (Sameer Agarwal) // -// Helpers for making CostFunctions as needed by the least squares framework, -// with Jacobians computed via automatic differentiation. For more information -// on automatic differentation, see the wikipedia article at -// http://en.wikipedia.org/wiki/Automatic_differentiation +// Create CostFunctions as needed by the least squares framework, with +// Jacobians computed via automatic differentiation. For more +// information on automatic differentation, see the wikipedia article +// at http://en.wikipedia.org/wiki/Automatic_differentiation // // To get an auto differentiated cost function, you must define a class with a // templated operator() (a functor) that computes the cost function in terms of @@ -57,8 +57,8 @@ // To write an auto-differentiable cost function for the above model, first // define the object // -// class MyScalarCostFunction { -// MyScalarCostFunction(double k): k_(k) {} +// class MyScalarCostFunctor { +// MyScalarCostFunctor(double k): k_(k) {} // // template // bool operator()(const T* const x , const T* const y, T* e) const { @@ -80,32 +80,32 @@ // it can be constructed as follows. // // CostFunction* cost_function -// = new AutoDiffCostFunction( -// new MyScalarCostFunction(1.0)); ^ ^ ^ -// | | | -// Dimension of residual ------+ | | -// Dimension of x ----------------+ | -// Dimension of y -------------------+ +// = new AutoDiffCostFunction( +// new MyScalarCostFunctor(1.0)); ^ ^ ^ +// | | | +// Dimension of residual -----+ | | +// Dimension of x ---------------+ | +// Dimension of y ------------------+ // // In this example, there is usually an instance for each measumerent of k. // // In the instantiation above, the template parameters following -// "MyScalarCostFunction", "1, 2, 2", describe the functor as computing a +// "MyScalarCostFunctor", "1, 2, 2", describe the functor as computing a // 1-dimensional output from two arguments, both 2-dimensional. // // The autodiff cost function also supports cost functions with a // runtime-determined number of residuals. For example: // // CostFunction* cost_function -// = new AutoDiffCostFunction( -// new CostFunctionWithDynamicNumResiduals(1.0), ^ ^ ^ -// runtime_number_of_residuals); <----+ | | | -// | | | | -// | | | | -// Actual number of residuals ------+ | | | -// Indicate dynamic number of residuals ---------+ | | -// Dimension of x -------------------------------------+ | -// Dimension of y ----------------------------------------+ +// = new AutoDiffCostFunction( +// new CostFunctorWithDynamicNumResiduals(1.0), ^ ^ ^ +// runtime_number_of_residuals); <----+ | | | +// | | | | +// | | | | +// Actual number of residuals ------+ | | | +// Indicate dynamic number of residuals --------+ | | +// Dimension of x ------------------------------------+ | +// Dimension of y ---------------------------------------+ // // The framework can currently accommodate cost functions of up to 6 independent // variables, and there is no limit on the dimensionality of each of them. @@ -119,7 +119,7 @@ // functions is to get the sizing wrong. In particular, there is a tendency to // set the template parameters to (dimension of residual, number of parameters) // instead of passing a dimension parameter for *every parameter*. In the -// example above, that would be , which is missing +// example above, that would be , which is missing // the last '2' argument. Please be careful when setting the size parameters. #ifndef CERES_PUBLIC_AUTODIFF_COST_FUNCTION_H_ @@ -154,16 +154,21 @@ template // Number of parameters in block 5. -class AutoDiffCostFunction : - public SizedCostFunction { + int N5 = 0, // Number of parameters in block 5. + int N6 = 0, // Number of parameters in block 6. + int N7 = 0, // Number of parameters in block 7. + int N8 = 0, // Number of parameters in block 8. + int N9 = 0> // Number of parameters in block 9. +class AutoDiffCostFunction : public SizedCostFunction { public: // Takes ownership of functor. Uses the template-provided value for the // number of residuals ("M"). explicit AutoDiffCostFunction(CostFunctor* functor) : functor_(functor) { CHECK_NE(M, DYNAMIC) << "Can't run the fixed-size constructor if the " - << "number of residuals is set to ceres::DYNAMIC."; + << "number of residuals is set to ceres::DYNAMIC."; } // Takes ownership of functor. Ignores the template-provided number of @@ -174,8 +179,9 @@ class AutoDiffCostFunction : AutoDiffCostFunction(CostFunctor* functor, int num_residuals) : functor_(functor) { CHECK_EQ(M, DYNAMIC) << "Can't run the dynamic-size constructor if the " - << "number of residuals is not ceres::DYNAMIC."; - SizedCostFunction::set_num_residuals(num_residuals); + << "number of residuals is not ceres::DYNAMIC."; + SizedCostFunction + ::set_num_residuals(num_residuals); } virtual ~AutoDiffCostFunction() {} @@ -190,14 +196,15 @@ class AutoDiffCostFunction : double** jacobians) const { if (!jacobians) { return internal::VariadicEvaluate< - CostFunctor, double, N0, N1, N2, N3, N4, N5> + CostFunctor, double, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9> ::Call(*functor_, parameters, residuals); } return internal::AutoDiff::Differentiate( + N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Differentiate( *functor_, parameters, - SizedCostFunction::num_residuals(), + SizedCostFunction + ::num_residuals(), residuals, jacobians); } diff --git a/extern/libmv/third_party/ceres/include/ceres/ceres.h b/extern/libmv/third_party/ceres/include/ceres/ceres.h index 22aaf8ff21a..7878806aa45 100644 --- a/extern/libmv/third_party/ceres/include/ceres/ceres.h +++ b/extern/libmv/third_party/ceres/include/ceres/ceres.h @@ -34,12 +34,20 @@ #ifndef CERES_PUBLIC_CERES_H_ #define CERES_PUBLIC_CERES_H_ +#define CERES_VERSION 1.5.0 +#define CERES_ABI_VERSION 1.5.0 + #include "ceres/autodiff_cost_function.h" #include "ceres/cost_function.h" +#include "ceres/cost_function_to_functor.h" +#include "ceres/crs_matrix.h" #include "ceres/iteration_callback.h" +#include "ceres/jet.h" #include "ceres/local_parameterization.h" #include "ceres/loss_function.h" #include "ceres/numeric_diff_cost_function.h" +#include "ceres/numeric_diff_functor.h" +#include "ceres/ordered_groups.h" #include "ceres/problem.h" #include "ceres/sized_cost_function.h" #include "ceres/solver.h" diff --git a/extern/libmv/third_party/ceres/include/ceres/cost_function_to_functor.h b/extern/libmv/third_party/ceres/include/ceres/cost_function_to_functor.h new file mode 100644 index 00000000000..b30ecd06983 --- /dev/null +++ b/extern/libmv/third_party/ceres/include/ceres/cost_function_to_functor.h @@ -0,0 +1,752 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2013 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) +// +// CostFunctionToFunctor is an adapter class that allows users to use +// CostFunction objects in templated functors which are to be used for +// automatic differentiation. This allows the user to seamlessly mix +// analytic, numeric and automatic differentiation. +// +// For example, let us assume that +// +// class IntrinsicProjection : public SizedCostFunction<2, 5, 3> { +// public: +// IntrinsicProjection(const double* observations); +// virtual bool Evaluate(double const* const* parameters, +// double* residuals, +// double** jacobians) const; +// }; +// +// is a cost function that implements the projection of a point in its +// local coordinate system onto its image plane and subtracts it from +// the observed point projection. It can compute its residual and +// either via analytic or numerical differentiation can compute its +// jacobians. +// +// Now we would like to compose the action of this CostFunction with +// the action of camera extrinsics, i.e., rotation and +// translation. Say we have a templated function +// +// template +// void RotateAndTranslatePoint(const T* rotation, +// const T* translation, +// const T* point, +// T* result); +// +// Then we can now do the following, +// +// struct CameraProjection { +// CameraProjection(double* observation) { +// intrinsic_projection_.reset( +// new CostFunctionToFunctor<2, 5, 3>( +// new IntrinsicProjection(observation_))); +// } +// template +// bool operator(const T* rotation, +// const T* translation, +// const T* intrinsics, +// const T* point, +// T* residual) const { +// T transformed_point[3]; +// RotateAndTranslatePoint(rotation, translation, point, transformed_point); +// +// // Note that we call intrinsic_projection_, just like it was +// // any other templated functor. +// +// return (*intrinsic_projection_)(intrinsics, transformed_point, residual); +// } +// +// private: +// scoped_ptr > intrinsic_projection_; +// }; + +#ifndef CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_ +#define CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_ + +#include +#include + +#include "ceres/cost_function.h" +#include "ceres/internal/fixed_array.h" +#include "ceres/internal/port.h" +#include "ceres/internal/scoped_ptr.h" + +namespace ceres { + +template +class CostFunctionToFunctor { + public: + explicit CostFunctionToFunctor(CostFunction* cost_function) + : cost_function_(cost_function) { + CHECK_NOTNULL(cost_function); + + CHECK_GE(kNumResiduals, 0); + CHECK_EQ(cost_function->num_residuals(), kNumResiduals); + + // This block breaks the 80 column rule to keep it somewhat readable. + CHECK((!N1 && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5 && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && (N9 > 0))) + << "Zero block cannot precede a non-zero block. Block sizes are " + << "(ignore trailing 0s): " << N0 << ", " << N1 << ", " << N2 << ", " + << N3 << ", " << N4 << ", " << N5 << ", " << N6 << ", " << N7 << ", " + << N8 << ", " << N9; + + const vector& parameter_block_sizes = + cost_function->parameter_block_sizes(); + const int num_parameter_blocks = + (N0 > 0) + (N1 > 0) + (N2 > 0) + (N3 > 0) + (N4 > 0) + + (N5 > 0) + (N6 > 0) + (N7 > 0) + (N8 > 0) + (N9 > 0); + CHECK_EQ(parameter_block_sizes.size(), num_parameter_blocks); + + CHECK_EQ(N0, parameter_block_sizes[0]); + if (parameter_block_sizes.size() > 1) CHECK_EQ(N1, parameter_block_sizes[1]); // NOLINT + if (parameter_block_sizes.size() > 2) CHECK_EQ(N2, parameter_block_sizes[2]); // NOLINT + if (parameter_block_sizes.size() > 3) CHECK_EQ(N3, parameter_block_sizes[3]); // NOLINT + if (parameter_block_sizes.size() > 4) CHECK_EQ(N4, parameter_block_sizes[4]); // NOLINT + if (parameter_block_sizes.size() > 5) CHECK_EQ(N5, parameter_block_sizes[5]); // NOLINT + if (parameter_block_sizes.size() > 6) CHECK_EQ(N6, parameter_block_sizes[6]); // NOLINT + if (parameter_block_sizes.size() > 7) CHECK_EQ(N7, parameter_block_sizes[7]); // NOLINT + if (parameter_block_sizes.size() > 8) CHECK_EQ(N8, parameter_block_sizes[8]); // NOLINT + if (parameter_block_sizes.size() > 9) CHECK_EQ(N9, parameter_block_sizes[9]); // NOLINT + + CHECK_EQ(accumulate(parameter_block_sizes.begin(), + parameter_block_sizes.end(), 0), + N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9); + } + + bool operator()(const double* x0, double* residuals) const { + CHECK_NE(N0, 0); + CHECK_EQ(N1, 0); + CHECK_EQ(N2, 0); + CHECK_EQ(N3, 0); + CHECK_EQ(N4, 0); + CHECK_EQ(N5, 0); + CHECK_EQ(N6, 0); + CHECK_EQ(N7, 0); + CHECK_EQ(N8, 0); + CHECK_EQ(N9, 0); + + return cost_function_->Evaluate(&x0, residuals, NULL); + } + + bool operator()(const double* x0, + const double* x1, + double* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_EQ(N2, 0); + CHECK_EQ(N3, 0); + CHECK_EQ(N4, 0); + CHECK_EQ(N5, 0); + CHECK_EQ(N6, 0); + CHECK_EQ(N7, 0); + CHECK_EQ(N8, 0); + CHECK_EQ(N9, 0); + internal::FixedArray parameter_blocks(2); + parameter_blocks[0] = x0; + parameter_blocks[1] = x1; + return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL); + } + + bool operator()(const double* x0, + const double* x1, + const double* x2, + double* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_NE(N2, 0); + CHECK_EQ(N3, 0); + CHECK_EQ(N4, 0); + CHECK_EQ(N5, 0); + CHECK_EQ(N6, 0); + CHECK_EQ(N7, 0); + CHECK_EQ(N8, 0); + CHECK_EQ(N9, 0); + internal::FixedArray parameter_blocks(3); + parameter_blocks[0] = x0; + parameter_blocks[1] = x1; + parameter_blocks[2] = x2; + return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL); + } + + bool operator()(const double* x0, + const double* x1, + const double* x2, + const double* x3, + double* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_NE(N2, 0); + CHECK_NE(N3, 0); + CHECK_EQ(N4, 0); + CHECK_EQ(N5, 0); + CHECK_EQ(N6, 0); + CHECK_EQ(N7, 0); + CHECK_EQ(N8, 0); + CHECK_EQ(N9, 0); + internal::FixedArray parameter_blocks(4); + parameter_blocks[0] = x0; + parameter_blocks[1] = x1; + parameter_blocks[2] = x2; + parameter_blocks[3] = x3; + return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL); + } + + bool operator()(const double* x0, + const double* x1, + const double* x2, + const double* x3, + const double* x4, + double* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_NE(N2, 0); + CHECK_NE(N3, 0); + CHECK_NE(N4, 0); + CHECK_EQ(N5, 0); + CHECK_EQ(N6, 0); + CHECK_EQ(N7, 0); + CHECK_EQ(N8, 0); + CHECK_EQ(N9, 0); + internal::FixedArray parameter_blocks(5); + parameter_blocks[0] = x0; + parameter_blocks[1] = x1; + parameter_blocks[2] = x2; + parameter_blocks[3] = x3; + parameter_blocks[4] = x4; + return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL); + } + + bool operator()(const double* x0, + const double* x1, + const double* x2, + const double* x3, + const double* x4, + const double* x5, + double* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_NE(N2, 0); + CHECK_NE(N3, 0); + CHECK_NE(N4, 0); + CHECK_NE(N5, 0); + CHECK_EQ(N6, 0); + CHECK_EQ(N7, 0); + CHECK_EQ(N8, 0); + CHECK_EQ(N9, 0); + internal::FixedArray parameter_blocks(6); + parameter_blocks[0] = x0; + parameter_blocks[1] = x1; + parameter_blocks[2] = x2; + parameter_blocks[3] = x3; + parameter_blocks[4] = x4; + parameter_blocks[5] = x5; + return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL); + } + + bool operator()(const double* x0, + const double* x1, + const double* x2, + const double* x3, + const double* x4, + const double* x5, + const double* x6, + double* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_NE(N2, 0); + CHECK_NE(N3, 0); + CHECK_NE(N4, 0); + CHECK_NE(N5, 0); + CHECK_NE(N6, 0); + CHECK_EQ(N7, 0); + CHECK_EQ(N8, 0); + CHECK_EQ(N9, 0); + internal::FixedArray parameter_blocks(7); + parameter_blocks[0] = x0; + parameter_blocks[1] = x1; + parameter_blocks[2] = x2; + parameter_blocks[3] = x3; + parameter_blocks[4] = x4; + parameter_blocks[5] = x5; + parameter_blocks[6] = x6; + return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL); + } + + bool operator()(const double* x0, + const double* x1, + const double* x2, + const double* x3, + const double* x4, + const double* x5, + const double* x6, + const double* x7, + double* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_NE(N2, 0); + CHECK_NE(N3, 0); + CHECK_NE(N4, 0); + CHECK_NE(N5, 0); + CHECK_NE(N6, 0); + CHECK_NE(N7, 0); + CHECK_EQ(N8, 0); + CHECK_EQ(N9, 0); + internal::FixedArray parameter_blocks(8); + parameter_blocks[0] = x0; + parameter_blocks[1] = x1; + parameter_blocks[2] = x2; + parameter_blocks[3] = x3; + parameter_blocks[4] = x4; + parameter_blocks[5] = x5; + parameter_blocks[6] = x6; + parameter_blocks[7] = x7; + return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL); + } + + bool operator()(const double* x0, + const double* x1, + const double* x2, + const double* x3, + const double* x4, + const double* x5, + const double* x6, + const double* x7, + const double* x8, + double* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_NE(N2, 0); + CHECK_NE(N3, 0); + CHECK_NE(N4, 0); + CHECK_NE(N5, 0); + CHECK_NE(N6, 0); + CHECK_NE(N7, 0); + CHECK_NE(N8, 0); + CHECK_EQ(N9, 0); + internal::FixedArray parameter_blocks(9); + parameter_blocks[0] = x0; + parameter_blocks[1] = x1; + parameter_blocks[2] = x2; + parameter_blocks[3] = x3; + parameter_blocks[4] = x4; + parameter_blocks[5] = x5; + parameter_blocks[6] = x6; + parameter_blocks[7] = x7; + parameter_blocks[8] = x8; + return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL); + } + + bool operator()(const double* x0, + const double* x1, + const double* x2, + const double* x3, + const double* x4, + const double* x5, + const double* x6, + const double* x7, + const double* x8, + const double* x9, + double* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_NE(N2, 0); + CHECK_NE(N3, 0); + CHECK_NE(N4, 0); + CHECK_NE(N5, 0); + CHECK_NE(N6, 0); + CHECK_NE(N7, 0); + CHECK_NE(N8, 0); + CHECK_NE(N9, 0); + internal::FixedArray parameter_blocks(10); + parameter_blocks[0] = x0; + parameter_blocks[1] = x1; + parameter_blocks[2] = x2; + parameter_blocks[3] = x3; + parameter_blocks[4] = x4; + parameter_blocks[5] = x5; + parameter_blocks[6] = x6; + parameter_blocks[7] = x7; + parameter_blocks[8] = x8; + parameter_blocks[9] = x9; + return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL); + } + + template + bool operator()(const JetT* x0, JetT* residuals) const { + CHECK_NE(N0, 0); + CHECK_EQ(N1, 0); + CHECK_EQ(N2, 0); + CHECK_EQ(N3, 0); + CHECK_EQ(N4, 0); + CHECK_EQ(N5, 0); + CHECK_EQ(N6, 0); + CHECK_EQ(N7, 0); + CHECK_EQ(N8, 0); + CHECK_EQ(N9, 0); + return EvaluateWithJets(&x0, residuals); + } + + template + bool operator()(const JetT* x0, + const JetT* x1, + JetT* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_EQ(N2, 0); + CHECK_EQ(N3, 0); + CHECK_EQ(N4, 0); + CHECK_EQ(N5, 0); + CHECK_EQ(N6, 0); + CHECK_EQ(N7, 0); + CHECK_EQ(N8, 0); + CHECK_EQ(N9, 0); + internal::FixedArray jets(2); + jets[0] = x0; + jets[1] = x1; + return EvaluateWithJets(jets.get(), residuals); + } + + template + bool operator()(const JetT* x0, + const JetT* x1, + const JetT* x2, + JetT* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_NE(N2, 0); + CHECK_EQ(N3, 0); + CHECK_EQ(N4, 0); + CHECK_EQ(N5, 0); + CHECK_EQ(N6, 0); + CHECK_EQ(N7, 0); + CHECK_EQ(N8, 0); + CHECK_EQ(N9, 0); + internal::FixedArray jets(3); + jets[0] = x0; + jets[1] = x1; + jets[2] = x2; + return EvaluateWithJets(jets.get(), residuals); + } + + template + bool operator()(const JetT* x0, + const JetT* x1, + const JetT* x2, + const JetT* x3, + JetT* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_NE(N2, 0); + CHECK_NE(N3, 0); + CHECK_EQ(N4, 0); + CHECK_EQ(N5, 0); + CHECK_EQ(N6, 0); + CHECK_EQ(N7, 0); + CHECK_EQ(N8, 0); + CHECK_EQ(N9, 0); + internal::FixedArray jets(4); + jets[0] = x0; + jets[1] = x1; + jets[2] = x2; + jets[3] = x3; + return EvaluateWithJets(jets.get(), residuals); + } + + template + bool operator()(const JetT* x0, + const JetT* x1, + const JetT* x2, + const JetT* x3, + const JetT* x4, + JetT* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_NE(N2, 0); + CHECK_NE(N3, 0); + CHECK_NE(N4, 0); + CHECK_EQ(N5, 0); + CHECK_EQ(N6, 0); + CHECK_EQ(N7, 0); + CHECK_EQ(N8, 0); + CHECK_EQ(N9, 0); + internal::FixedArray jets(5); + jets[0] = x0; + jets[1] = x1; + jets[2] = x2; + jets[3] = x3; + jets[4] = x4; + return EvaluateWithJets(jets.get(), residuals); + } + + template + bool operator()(const JetT* x0, + const JetT* x1, + const JetT* x2, + const JetT* x3, + const JetT* x4, + const JetT* x5, + JetT* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_NE(N2, 0); + CHECK_NE(N3, 0); + CHECK_NE(N4, 0); + CHECK_NE(N5, 0); + CHECK_EQ(N6, 0); + CHECK_EQ(N7, 0); + CHECK_EQ(N8, 0); + CHECK_EQ(N9, 0); + internal::FixedArray jets(6); + jets[0] = x0; + jets[1] = x1; + jets[2] = x2; + jets[3] = x3; + jets[4] = x4; + jets[5] = x5; + return EvaluateWithJets(jets.get(), residuals); + } + + template + bool operator()(const JetT* x0, + const JetT* x1, + const JetT* x2, + const JetT* x3, + const JetT* x4, + const JetT* x5, + const JetT* x6, + JetT* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_NE(N2, 0); + CHECK_NE(N3, 0); + CHECK_NE(N4, 0); + CHECK_NE(N5, 0); + CHECK_NE(N6, 0); + CHECK_EQ(N7, 0); + CHECK_EQ(N8, 0); + CHECK_EQ(N9, 0); + internal::FixedArray jets(7); + jets[0] = x0; + jets[1] = x1; + jets[2] = x2; + jets[3] = x3; + jets[4] = x4; + jets[5] = x5; + jets[6] = x6; + return EvaluateWithJets(jets.get(), residuals); + } + + template + bool operator()(const JetT* x0, + const JetT* x1, + const JetT* x2, + const JetT* x3, + const JetT* x4, + const JetT* x5, + const JetT* x6, + const JetT* x7, + JetT* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_NE(N2, 0); + CHECK_NE(N3, 0); + CHECK_NE(N4, 0); + CHECK_NE(N5, 0); + CHECK_NE(N6, 0); + CHECK_NE(N7, 0); + CHECK_EQ(N8, 0); + CHECK_EQ(N9, 0); + internal::FixedArray jets(8); + jets[0] = x0; + jets[1] = x1; + jets[2] = x2; + jets[3] = x3; + jets[4] = x4; + jets[5] = x5; + jets[6] = x6; + jets[7] = x7; + return EvaluateWithJets(jets.get(), residuals); + } + + template + bool operator()(const JetT* x0, + const JetT* x1, + const JetT* x2, + const JetT* x3, + const JetT* x4, + const JetT* x5, + const JetT* x6, + const JetT* x7, + const JetT* x8, + JetT* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_NE(N2, 0); + CHECK_NE(N3, 0); + CHECK_NE(N4, 0); + CHECK_NE(N5, 0); + CHECK_NE(N6, 0); + CHECK_NE(N7, 0); + CHECK_NE(N8, 0); + CHECK_EQ(N9, 0); + internal::FixedArray jets(9); + jets[0] = x0; + jets[1] = x1; + jets[2] = x2; + jets[3] = x3; + jets[4] = x4; + jets[5] = x5; + jets[6] = x6; + jets[7] = x7; + jets[8] = x8; + return EvaluateWithJets(jets.get(), residuals); + } + + template + bool operator()(const JetT* x0, + const JetT* x1, + const JetT* x2, + const JetT* x3, + const JetT* x4, + const JetT* x5, + const JetT* x6, + const JetT* x7, + const JetT* x8, + const JetT* x9, + JetT* residuals) const { + CHECK_NE(N0, 0); + CHECK_NE(N1, 0); + CHECK_NE(N2, 0); + CHECK_NE(N3, 0); + CHECK_NE(N4, 0); + CHECK_NE(N5, 0); + CHECK_NE(N6, 0); + CHECK_NE(N7, 0); + CHECK_NE(N8, 0); + CHECK_NE(N9, 0); + internal::FixedArray jets(10); + jets[0] = x0; + jets[1] = x1; + jets[2] = x2; + jets[3] = x3; + jets[4] = x4; + jets[5] = x5; + jets[6] = x6; + jets[7] = x7; + jets[8] = x8; + jets[9] = x9; + return EvaluateWithJets(jets.get(), residuals); + } + + private: + template + bool EvaluateWithJets(const JetT** inputs, JetT* output) const { + const int kNumParameters = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9; + const vector& parameter_block_sizes = + cost_function_->parameter_block_sizes(); + const int num_parameter_blocks = parameter_block_sizes.size(); + const int num_residuals = cost_function_->num_residuals(); + + internal::FixedArray parameters(kNumParameters); + internal::FixedArray parameter_blocks(num_parameter_blocks); + internal::FixedArray jacobians(num_residuals * kNumParameters); + internal::FixedArray jacobian_blocks(num_parameter_blocks); + internal::FixedArray residuals(num_residuals); + + // Build a set of arrays to get the residuals and jacobians from + // the CostFunction wrapped by this functor. + double* parameter_ptr = parameters.get(); + double* jacobian_ptr = jacobians.get(); + for (int i = 0; i < num_parameter_blocks; ++i) { + parameter_blocks[i] = parameter_ptr; + jacobian_blocks[i] = jacobian_ptr; + for (int j = 0; j < parameter_block_sizes[i]; ++j) { + *parameter_ptr++ = inputs[i][j].a; + } + jacobian_ptr += num_residuals * parameter_block_sizes[i]; + } + + if (!cost_function_->Evaluate(parameter_blocks.get(), + residuals.get(), + jacobian_blocks.get())) { + return false; + } + + // Now that we have the incoming Jets, which are carrying the + // partial derivatives of each of the inputs w.r.t to some other + // underlying parameters. The derivative of the outputs of the + // cost function w.r.t to the same underlying parameters can now + // be computed by applying the chain rule. + // + // d output[i] d output[i] d input[j] + // -------------- = sum_j ----------- * ------------ + // d parameter[k] d input[j] d parameter[k] + // + // d input[j] + // -------------- = inputs[j], so + // d parameter[k] + // + // outputJet[i] = sum_k jacobian[i][k] * inputJet[k] + // + // The following loop, iterates over the residuals, computing one + // output jet at a time. + for (int i = 0; i < num_residuals; ++i) { + output[i].a = residuals[i]; + output[i].v.setZero(); + + for (int j = 0; j < num_parameter_blocks; ++j) { + const int16 block_size = parameter_block_sizes[j]; + for (int k = 0; k < parameter_block_sizes[j]; ++k) { + output[i].v += + jacobian_blocks[j][i * block_size + k] * inputs[j][k].v; + } + } + } + + return true; + } + + private: + internal::scoped_ptr cost_function_; +}; + +} // namespace ceres + +#endif // CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_ diff --git a/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h b/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h index c9fe8f78b7c..8c470cd33f2 100644 --- a/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h +++ b/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h @@ -44,17 +44,35 @@ struct CRSMatrix { int num_rows; int num_cols; - // A compressed row matrix stores its contents in three arrays. - // The non-zero pattern of the i^th row is given by + // A compressed row matrix stores its contents in three arrays, + // rows, cols and values. // - // rows[cols[i] ... cols[i + 1]] + // rows is a num_rows + 1 sized array that points into the cols and + // values array. For each row i: // - // and the corresponding values by + // cols[rows[i]] ... cols[rows[i + 1] - 1] are the indices of the + // non-zero columns of row i. // - // values[cols[i] ... cols[i + 1]] + // values[rows[i]] .. values[rows[i + 1] - 1] are the values of the + // corresponding entries. // - // Thus, cols is a vector of size num_cols + 1, and rows and values - // have as many entries as number of non-zeros in the matrix. + // cols and values contain as many entries as there are non-zeros in + // the matrix. + // + // e.g, consider the 3x4 sparse matrix + // + // [ 0 10 0 4 ] + // [ 0 2 -3 2 ] + // [ 1 2 0 0 ] + // + // The three arrays will be: + // + // + // -row0- ---row1--- -row2- + // rows = [ 0, 2, 5, 7] + // cols = [ 1, 3, 1, 2, 3, 0, 1] + // values = [10, 4, 2, -3, 2, 1, 2] + vector cols; vector rows; vector values; diff --git a/extern/libmv/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h b/extern/libmv/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h new file mode 100644 index 00000000000..861164a8253 --- /dev/null +++ b/extern/libmv/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h @@ -0,0 +1,215 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: mierle@gmail.com (Keir Mierle) +// sameeragarwal@google.com (Sameer Agarwal) +// thadh@gmail.com (Thad Hughes) +// +// This autodiff implementation differs from the one found in +// autodiff_cost_function.h by supporting autodiff on cost functions with +// variable numbers of parameters with variable sizes. With the other +// implementation, all the sizes (both the number of parameter blocks and the +// size of each block) must be fixed at compile time. +// +// The functor API differs slightly from the API for fixed size autodiff; the +// expected interface for the cost functors is: +// +// struct MyCostFunctor { +// template +// bool operator()(T const* const* parameters, T* residuals) const { +// // Use parameters[i] to access the i'th parameter block. +// } +// } +// +// Since the sizing of the parameters is done at runtime, you must also specify +// the sizes after creating the dynamic autodiff cost function. For example: +// +// DynamicAutoDiffCostFunction cost_function( +// new MyCostFunctor()); +// cost_function.AddParameterBlock(5); +// cost_function.AddParameterBlock(10); +// cost_function.SetNumResiduals(21); +// +// Under the hood, the implementation evaluates the cost function multiple +// times, computing a small set of the derivatives (four by default, controlled +// by the Stride template parameter) with each pass. There is a tradeoff with +// the size of the passes; you may want to experiment with the stride. + +#ifndef CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_ +#define CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_ + +#include +#include +#include + +#include "ceres/cost_function.h" +#include "ceres/internal/scoped_ptr.h" +#include "ceres/jet.h" +#include "glog/logging.h" + +namespace ceres { + +template +class DynamicAutoDiffCostFunction : public CostFunction { + public: + explicit DynamicAutoDiffCostFunction(CostFunctor* functor) + : functor_(functor) {} + + virtual ~DynamicAutoDiffCostFunction() {} + + void AddParameterBlock(int size) { + mutable_parameter_block_sizes()->push_back(size); + } + + void SetNumResiduals(int num_residuals) { + set_num_residuals(num_residuals); + } + + virtual bool Evaluate(double const* const* parameters, + double* residuals, + double** jacobians) const { + CHECK_GT(num_residuals(), 0) + << "You must call DynamicAutoDiffCostFunction::SetNumResiduals() " + << "before DynamicAutoDiffCostFunction::Evaluate()."; + + if (jacobians == NULL) { + return (*functor_)(parameters, residuals); + } + + // The difficulty with Jets, as implemented in Ceres, is that they were + // originally designed for strictly compile-sized use. At this point, there + // is a large body of code that assumes inside a cost functor it is + // acceptable to do e.g. T(1.5) and get an appropriately sized jet back. + // + // Unfortunately, it is impossible to communicate the expected size of a + // dynamically sized jet to the static instantiations that existing code + // depends on. + // + // To work around this issue, the solution here is to evaluate the + // jacobians in a series of passes, each one computing Stripe * + // num_residuals() derivatives. This is done with small, fixed-size jets. + const int num_parameter_blocks = parameter_block_sizes().size(); + const int num_parameters = std::accumulate(parameter_block_sizes().begin(), + parameter_block_sizes().end(), + 0); + + // Allocate scratch space for the strided evaluation. + vector > input_jets(num_parameters); + vector > output_jets(num_residuals()); + + // Make the parameter pack that is sent to the functor (reused). + vector* > jet_parameters(num_parameter_blocks, NULL); + int num_active_parameters = 0; + int start_derivative_section = -1; + for (int i = 0, parameter_cursor = 0; i < num_parameter_blocks; ++i) { + jet_parameters[i] = &input_jets[parameter_cursor]; + + const int parameter_block_size = parameter_block_sizes()[i]; + if (jacobians[i] != NULL) { + start_derivative_section = + (start_derivative_section == -1) + ? parameter_cursor + : start_derivative_section; + num_active_parameters += parameter_block_size; + } + + for (int j = 0; j < parameter_block_size; ++j, parameter_cursor++) { + input_jets[parameter_cursor].a = parameters[i][j]; + } + } + + // Evaluate all of the strides. Each stride is a chunk of the derivative to + // evaluate, typically some size proportional to the size of the SIMD + // registers of the CPU. + int num_strides = static_cast(ceil(num_active_parameters / + static_cast(Stride))); + + for (int pass = 0; pass < num_strides; ++pass) { + // Set most of the jet components to zero, except for + // non-constant #Stride parameters. + int active_parameter_count = 0; + int end_derivative_section = start_derivative_section; + for (int i = 0, parameter_cursor = 0; i < num_parameter_blocks; ++i) { + for (int j = 0; j < parameter_block_sizes()[i]; + ++j, parameter_cursor++) { + input_jets[parameter_cursor].v.setZero(); + if (parameter_cursor >= start_derivative_section && + active_parameter_count < Stride) { + if (jacobians[i] != NULL) { + input_jets[parameter_cursor] + .v[parameter_cursor - start_derivative_section] = 1.0; + ++active_parameter_count; + } + ++end_derivative_section; + } + } + } + + if (!(*functor_)(&jet_parameters[0], &output_jets[0])) { + return false; + } + + // Copy the pieces of the jacobians into their final place. + active_parameter_count = 0; + for (int i = 0, parameter_cursor = 0; i < num_parameter_blocks; ++i) { + for (int j = 0; j < parameter_block_sizes()[i]; + ++j, parameter_cursor++) { + if (parameter_cursor >= start_derivative_section && + active_parameter_count < Stride) { + if (jacobians[i] != NULL) { + for (int k = 0; k < num_residuals(); ++k) { + jacobians[i][k * parameter_block_sizes()[i] + j] = + output_jets[k].v[parameter_cursor - + start_derivative_section]; + } + ++active_parameter_count; + } + } + } + } + + // Only copy the residuals over once (even though we compute them on + // every loop). + if (pass == num_strides - 1) { + for (int k = 0; k < num_residuals(); ++k) { + residuals[k] = output_jets[k].a; + } + } + + start_derivative_section = end_derivative_section; + } + return true; + } + + private: + internal::scoped_ptr functor_; +}; + +} // namespace ceres + +#endif // CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_ diff --git a/extern/libmv/third_party/ceres/include/ceres/fpclassify.h b/extern/libmv/third_party/ceres/include/ceres/fpclassify.h index 5a9ea1599d2..b730832fd4b 100644 --- a/extern/libmv/third_party/ceres/include/ceres/fpclassify.h +++ b/extern/libmv/third_party/ceres/include/ceres/fpclassify.h @@ -41,6 +41,8 @@ #include #endif +#include + namespace ceres { #if defined(_MSC_VER) diff --git a/extern/libmv/third_party/ceres/include/ceres/gradient_checker.h b/extern/libmv/third_party/ceres/include/ceres/gradient_checker.h new file mode 100644 index 00000000000..3ec8056a02d --- /dev/null +++ b/extern/libmv/third_party/ceres/include/ceres/gradient_checker.h @@ -0,0 +1,222 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2010, 2011, 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// Copyright 2007 Google Inc. All Rights Reserved. +// +// Author: wjr@google.com (William Rucklidge) +// +// This file contains a class that exercises a cost function, to make sure +// that it is computing reasonable derivatives. It compares the Jacobians +// computed by the cost function with those obtained by finite +// differences. + +#ifndef CERES_PUBLIC_GRADIENT_CHECKER_H_ +#define CERES_PUBLIC_GRADIENT_CHECKER_H_ + +#include +#include +#include + +#include "ceres/internal/eigen.h" +#include "ceres/internal/fixed_array.h" +#include "ceres/internal/macros.h" +#include "ceres/internal/scoped_ptr.h" +#include "ceres/numeric_diff_cost_function.h" +#include "glog/logging.h" + +namespace ceres { + +// An object that exercises a cost function, to compare the answers that it +// gives with derivatives estimated using finite differencing. +// +// The only likely usage of this is for testing. +// +// How to use: Fill in an array of pointers to parameter blocks for your +// CostFunction, and then call Probe(). Check that the return value is +// 'true'. See prober_test.cc for an example. +// +// This is templated similarly to NumericDiffCostFunction, as it internally +// uses that. +template +class GradientChecker { + public: + // Here we stash some results from the probe, for later + // inspection. + struct GradientCheckResults { + // Computed cost. + Vector cost; + + // The sizes of these matrices are dictated by the cost function's + // parameter and residual block sizes. Each vector's length will + // term->parameter_block_sizes().size(), and each matrix is the + // Jacobian of the residual with respect to the corresponding parameter + // block. + + // Derivatives as computed by the cost function. + vector term_jacobians; + + // Derivatives as computed by finite differencing. + vector finite_difference_jacobians; + + // Infinity-norm of term_jacobians - finite_difference_jacobians. + double error_jacobians; + }; + + // Checks the Jacobian computed by a cost function. + // + // probe_point: The parameter values at which to probe. + // error_tolerance: A threshold for the infinity-norm difference + // between the Jacobians. If the Jacobians differ by more than + // this amount, then the probe fails. + // + // term: The cost function to test. Not retained after this call returns. + // + // results: On return, the two Jacobians (and other information) + // will be stored here. May be NULL. + // + // Returns true if no problems are detected and the difference between the + // Jacobians is less than error_tolerance. + static bool Probe(double const* const* probe_point, + double error_tolerance, + CostFunctionToProbe *term, + GradientCheckResults* results) { + CHECK_NOTNULL(probe_point); + CHECK_NOTNULL(term); + LOG(INFO) << "-------------------- Starting Probe() --------------------"; + + // We need a GradientCheckeresults, whether or not they supplied one. + internal::scoped_ptr owned_results; + if (results == NULL) { + owned_results.reset(new GradientCheckResults); + results = owned_results.get(); + } + + // Do a consistency check between the term and the template parameters. + CHECK_EQ(M, term->num_residuals()); + const int num_residuals = M; + const vector& block_sizes = term->parameter_block_sizes(); + const int num_blocks = block_sizes.size(); + + CHECK_LE(num_blocks, 5) << "Unable to test functions that take more " + << "than 5 parameter blocks"; + if (N0) { + CHECK_EQ(N0, block_sizes[0]); + CHECK_GE(num_blocks, 1); + } else { + CHECK_LT(num_blocks, 1); + } + if (N1) { + CHECK_EQ(N1, block_sizes[1]); + CHECK_GE(num_blocks, 2); + } else { + CHECK_LT(num_blocks, 2); + } + if (N2) { + CHECK_EQ(N2, block_sizes[2]); + CHECK_GE(num_blocks, 3); + } else { + CHECK_LT(num_blocks, 3); + } + if (N3) { + CHECK_EQ(N3, block_sizes[3]); + CHECK_GE(num_blocks, 4); + } else { + CHECK_LT(num_blocks, 4); + } + if (N4) { + CHECK_EQ(N4, block_sizes[4]); + CHECK_GE(num_blocks, 5); + } else { + CHECK_LT(num_blocks, 5); + } + + results->term_jacobians.clear(); + results->term_jacobians.resize(num_blocks); + results->finite_difference_jacobians.clear(); + results->finite_difference_jacobians.resize(num_blocks); + + internal::FixedArray term_jacobian_pointers(num_blocks); + internal::FixedArray + finite_difference_jacobian_pointers(num_blocks); + for (int i = 0; i < num_blocks; i++) { + results->term_jacobians[i].resize(num_residuals, block_sizes[i]); + term_jacobian_pointers[i] = results->term_jacobians[i].data(); + results->finite_difference_jacobians[i].resize( + num_residuals, block_sizes[i]); + finite_difference_jacobian_pointers[i] = + results->finite_difference_jacobians[i].data(); + } + results->cost.resize(num_residuals, 1); + + CHECK(term->Evaluate(probe_point, results->cost.data(), + term_jacobian_pointers.get())); + NumericDiffCostFunction + numeric_term(term, DO_NOT_TAKE_OWNERSHIP); + CHECK(numeric_term.Evaluate(probe_point, results->cost.data(), + finite_difference_jacobian_pointers.get())); + + results->error_jacobians = 0; + for (int i = 0; i < num_blocks; i++) { + Matrix jacobian_difference = results->term_jacobians[i] - + results->finite_difference_jacobians[i]; + results->error_jacobians = + std::max(results->error_jacobians, + jacobian_difference.lpNorm()); + } + + LOG(INFO) << "========== term-computed derivatives =========="; + for (int i = 0; i < num_blocks; i++) { + LOG(INFO) << "term_computed block " << i; + LOG(INFO) << "\n" << results->term_jacobians[i]; + } + + LOG(INFO) << "========== finite-difference derivatives =========="; + for (int i = 0; i < num_blocks; i++) { + LOG(INFO) << "finite_difference block " << i; + LOG(INFO) << "\n" << results->finite_difference_jacobians[i]; + } + + LOG(INFO) << "========== difference =========="; + for (int i = 0; i < num_blocks; i++) { + LOG(INFO) << "difference block " << i; + LOG(INFO) << (results->term_jacobians[i] - + results->finite_difference_jacobians[i]); + } + + LOG(INFO) << "||difference|| = " << results->error_jacobians; + + return results->error_jacobians < error_tolerance; + } + + private: + CERES_DISALLOW_IMPLICIT_CONSTRUCTORS(GradientChecker); +}; + +} // namespace ceres + +#endif // CERES_PUBLIC_GRADIENT_CHECKER_H_ diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h b/extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h index 4f5081f8f66..011f2a05b65 100644 --- a/extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h +++ b/extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h @@ -146,6 +146,7 @@ #include "ceres/jet.h" #include "ceres/internal/eigen.h" #include "ceres/internal/fixed_array.h" +#include "ceres/internal/variadic_evaluate.h" namespace ceres { namespace internal { @@ -191,134 +192,71 @@ inline void Take1stOrderPart(const int M, const JetT *src, T *dst) { DCHECK(src); DCHECK(dst); for (int i = 0; i < M; ++i) { - Eigen::Map >(dst + N * i, N) = src[i].v.template segment(N0); + Eigen::Map >(dst + N * i, N) = + src[i].v.template segment(N0); } } -// This block of quasi-repeated code calls the user-supplied functor, which may -// take a variable number of arguments. This is accomplished by specializing the -// struct based on the size of the trailing parameters; parameters with 0 size -// are assumed missing. -// -// Supporting variadic functions is the primary source of complexity in the -// autodiff implementation. - -template -struct VariadicEvaluate { - static bool Call(const Functor& functor, T const *const *input, T* output) { - return functor(input[0], - input[1], - input[2], - input[3], - input[4], - input[5], - output); - } -}; - -template -struct VariadicEvaluate { - static bool Call(const Functor& functor, T const *const *input, T* output) { - return functor(input[0], - input[1], - input[2], - input[3], - input[4], - output); - } -}; - -template -struct VariadicEvaluate { - static bool Call(const Functor& functor, T const *const *input, T* output) { - return functor(input[0], - input[1], - input[2], - input[3], - output); - } -}; - -template -struct VariadicEvaluate { - static bool Call(const Functor& functor, T const *const *input, T* output) { - return functor(input[0], - input[1], - input[2], - output); - } -}; - -template -struct VariadicEvaluate { - static bool Call(const Functor& functor, T const *const *input, T* output) { - return functor(input[0], - input[1], - output); - } -}; - -template -struct VariadicEvaluate { - static bool Call(const Functor& functor, T const *const *input, T* output) { - return functor(input[0], - output); - } -}; - -// This is in a struct because default template parameters on a function are not -// supported in C++03 (though it is available in C++0x). N0 through N5 are the -// dimension of the input arguments to the user supplied functor. +// This is in a struct because default template parameters on a +// function are not supported in C++03 (though it is available in +// C++0x). N0 through N5 are the dimension of the input arguments to +// the user supplied functor. template + int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0, + int N5 = 0, int N6 = 0, int N7 = 0, int N8 = 0, int N9 = 0> struct AutoDiff { static bool Differentiate(const Functor& functor, T const *const *parameters, int num_outputs, T *function_value, T **jacobians) { - typedef Jet JetT; - - DCHECK_GT(N0, 0) - << "Cost functions must have at least one parameter block."; - DCHECK((!N1 && !N2 && !N3 && !N4 && !N5) || - ((N1 > 0) && !N2 && !N3 && !N4 && !N5) || - ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5) || - ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5) || - ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5) || - ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0))) + // This block breaks the 80 column rule to keep it somewhat readable. + DCHECK_GT(num_outputs, 0); + CHECK((!N1 && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5 && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && (N9 > 0))) << "Zero block cannot precede a non-zero block. Block sizes are " << "(ignore trailing 0s): " << N0 << ", " << N1 << ", " << N2 << ", " - << N3 << ", " << N4 << ", " << N5; - - DCHECK_GT(num_outputs, 0); + << N3 << ", " << N4 << ", " << N5 << ", " << N6 << ", " << N7 << ", " + << N8 << ", " << N9; + typedef Jet JetT; FixedArray x( - N0 + N1 + N2 + N3 + N4 + N5 + num_outputs); + N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9 + num_outputs); - // It's ugly, but it works. - const int jet0 = 0; - const int jet1 = N0; - const int jet2 = N0 + N1; - const int jet3 = N0 + N1 + N2; - const int jet4 = N0 + N1 + N2 + N3; - const int jet5 = N0 + N1 + N2 + N3 + N4; - const int jet6 = N0 + N1 + N2 + N3 + N4 + N5; + // These are the positions of the respective jets in the fixed array x. + const int jet0 = 0; + const int jet1 = N0; + const int jet2 = N0 + N1; + const int jet3 = N0 + N1 + N2; + const int jet4 = N0 + N1 + N2 + N3; + const int jet5 = N0 + N1 + N2 + N3 + N4; + const int jet6 = N0 + N1 + N2 + N3 + N4 + N5; + const int jet7 = N0 + N1 + N2 + N3 + N4 + N5 + N6; + const int jet8 = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7; + const int jet9 = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8; - const JetT *unpacked_parameters[6] = { + const JetT *unpacked_parameters[10] = { x.get() + jet0, x.get() + jet1, x.get() + jet2, x.get() + jet3, x.get() + jet4, x.get() + jet5, + x.get() + jet6, + x.get() + jet7, + x.get() + jet8, + x.get() + jet9, }; - JetT *output = x.get() + jet6; + + JetT* output = x.get() + N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9; #define CERES_MAKE_1ST_ORDER_PERTURBATION(i) \ if (N ## i) { \ @@ -333,10 +271,14 @@ struct AutoDiff { CERES_MAKE_1ST_ORDER_PERTURBATION(3); CERES_MAKE_1ST_ORDER_PERTURBATION(4); CERES_MAKE_1ST_ORDER_PERTURBATION(5); + CERES_MAKE_1ST_ORDER_PERTURBATION(6); + CERES_MAKE_1ST_ORDER_PERTURBATION(7); + CERES_MAKE_1ST_ORDER_PERTURBATION(8); + CERES_MAKE_1ST_ORDER_PERTURBATION(9); #undef CERES_MAKE_1ST_ORDER_PERTURBATION if (!VariadicEvaluate::Call( + N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Call( functor, unpacked_parameters, output)) { return false; } @@ -359,6 +301,10 @@ struct AutoDiff { CERES_TAKE_1ST_ORDER_PERTURBATION(3); CERES_TAKE_1ST_ORDER_PERTURBATION(4); CERES_TAKE_1ST_ORDER_PERTURBATION(5); + CERES_TAKE_1ST_ORDER_PERTURBATION(6); + CERES_TAKE_1ST_ORDER_PERTURBATION(7); + CERES_TAKE_1ST_ORDER_PERTURBATION(8); + CERES_TAKE_1ST_ORDER_PERTURBATION(9); #undef CERES_TAKE_1ST_ORDER_PERTURBATION return true; } diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h b/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h index ce777d22dc7..fa4a339d757 100644 --- a/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h +++ b/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h @@ -168,11 +168,11 @@ inline FixedArray::FixedArray(typename FixedArray::size_type n) array_((n <= kInlineElements ? reinterpret_cast(inline_space_) : new InnerContainer[n])) { - DCHECK_GE(n, 0); + DCHECK_GE(n, size_t(0)); // Construct only the elements actually used. if (array_ == reinterpret_cast(inline_space_)) { - for (int i = 0; i != size_; ++i) { + for (size_t i = 0; i != size_; ++i) { inline_space_[i].Init(); } } @@ -183,7 +183,7 @@ inline FixedArray::~FixedArray() { if (array_ != reinterpret_cast(inline_space_)) { delete[] array_; } else { - for (int i = 0; i != size_; ++i) { + for (size_t i = 0; i != size_; ++i) { inline_space_[i].Destroy(); } } diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/macros.h b/extern/libmv/third_party/ceres/include/ceres/internal/macros.h index 83ec31193e7..388cf30fe70 100644 --- a/extern/libmv/third_party/ceres/include/ceres/internal/macros.h +++ b/extern/libmv/third_party/ceres/include/ceres/internal/macros.h @@ -132,16 +132,16 @@ char (&ArraySizeHelper(const T (&array)[N]))[N]; // - wan 2005-11-16 // // Starting with Visual C++ 2005, WinNT.h includes ARRAYSIZE. However, -// the definition comes from the over-broad windows.h header that +// the definition comes from the over-broad windows.h header that // introduces a macro, ERROR, that conflicts with the logging framework // that Ceres uses. Instead, rename ARRAYSIZE to CERES_ARRAYSIZE. -#define CERES_ARRAYSIZE(a) \ - ((sizeof(a) / sizeof(*(a))) / \ +#define CERES_ARRAYSIZE(a) \ + ((sizeof(a) / sizeof(*(a))) / \ static_cast(!(sizeof(a) % sizeof(*(a))))) -// Tell the compiler to warn about unused return values for functions declared -// with this macro. The macro should be used on function declarations -// following the argument list: +// Tell the compiler to warn about unused return values for functions +// declared with this macro. The macro should be used on function +// declarations following the argument list: // // Sprocket* AllocateSprocket() MUST_USE_RESULT; // diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h b/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h index 174d35ee2bd..7ea723d2a83 100644 --- a/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h +++ b/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h @@ -110,56 +110,61 @@ class ManualConstructor { inline Type& operator*() { return *get(); } inline const Type& operator*() const { return *get(); } + // This is needed to get around the strict aliasing warning GCC generates. + inline void* space() { + return reinterpret_cast(space_); + } + // You can pass up to four constructor arguments as arguments of Init(). inline void Init() { - new(space_) Type; + new(space()) Type; } template inline void Init(const T1& p1) { - new(space_) Type(p1); + new(space()) Type(p1); } template inline void Init(const T1& p1, const T2& p2) { - new(space_) Type(p1, p2); + new(space()) Type(p1, p2); } template inline void Init(const T1& p1, const T2& p2, const T3& p3) { - new(space_) Type(p1, p2, p3); + new(space()) Type(p1, p2, p3); } template inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4) { - new(space_) Type(p1, p2, p3, p4); + new(space()) Type(p1, p2, p3, p4); } template inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4, const T5& p5) { - new(space_) Type(p1, p2, p3, p4, p5); + new(space()) Type(p1, p2, p3, p4, p5); } template inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4, const T5& p5, const T6& p6) { - new(space_) Type(p1, p2, p3, p4, p5, p6); + new(space()) Type(p1, p2, p3, p4, p5, p6); } template inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4, const T5& p5, const T6& p6, const T7& p7) { - new(space_) Type(p1, p2, p3, p4, p5, p6, p7); + new(space()) Type(p1, p2, p3, p4, p5, p6, p7); } template inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4, const T5& p5, const T6& p6, const T7& p7, const T8& p8) { - new(space_) Type(p1, p2, p3, p4, p5, p6, p7, p8); + new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8); } template + +#include "Eigen/Dense" +#include "ceres/cost_function.h" +#include "ceres/internal/scoped_ptr.h" +#include "ceres/internal/variadic_evaluate.h" +#include "ceres/types.h" +#include "glog/logging.h" + + +namespace ceres { +namespace internal { + +// Helper templates that allow evaluation of a variadic functor or a +// CostFunction object. +template +bool EvaluateImpl(const CostFunctor* functor, + double const* const* parameters, + double* residuals, + const void* /* NOT USED */) { + return VariadicEvaluate::Call( + *functor, + parameters, + residuals); +} + +template +bool EvaluateImpl(const CostFunctor* functor, + double const* const* parameters, + double* residuals, + const CostFunction* /* NOT USED */) { + return functor->Evaluate(parameters, residuals, NULL); +} + +// This is split from the main class because C++ doesn't allow partial template +// specializations for member functions. The alternative is to repeat the main +// class for differing numbers of parameters, which is also unfortunate. +template +struct NumericDiff { + // Mutates parameters but must restore them before return. + static bool EvaluateJacobianForParameterBlock( + const CostFunctor* functor, + double const* residuals_at_eval_point, + const double relative_step_size, + double **parameters, + double *jacobian) { + using Eigen::Map; + using Eigen::Matrix; + using Eigen::RowMajor; + using Eigen::ColMajor; + + typedef Matrix ResidualVector; + typedef Matrix ParameterVector; + typedef Matrix 1) ? ColMajor : RowMajor> JacobianMatrix; + + + Map parameter_jacobian(jacobian, + kNumResiduals, + kParameterBlockSize); + + // Mutate 1 element at a time and then restore. + Map x_plus_delta(parameters[kParameterBlock], + kParameterBlockSize); + ParameterVector x(x_plus_delta); + ParameterVector step_size = x.array().abs() * relative_step_size; + + // To handle cases where a parameter is exactly zero, instead use + // the mean step_size for the other dimensions. If all the + // parameters are zero, there's no good answer. Take + // relative_step_size as a guess and hope for the best. + const double fallback_step_size = + (step_size.sum() == 0) + ? relative_step_size + : step_size.sum() / step_size.rows(); + + // For each parameter in the parameter block, use finite differences to + // compute the derivative for that parameter. + for (int j = 0; j < kParameterBlockSize; ++j) { + const double delta = + (step_size(j) == 0.0) ? fallback_step_size : step_size(j); + + x_plus_delta(j) = x(j) + delta; + + double residuals[kNumResiduals]; // NOLINT + + if (!EvaluateImpl( + functor, parameters, residuals, functor)) { + return false; + } + + // Compute this column of the jacobian in 3 steps: + // 1. Store residuals for the forward part. + // 2. Subtract residuals for the backward (or 0) part. + // 3. Divide out the run. + parameter_jacobian.col(j) = + Map(residuals, kNumResiduals); + + double one_over_delta = 1.0 / delta; + if (kMethod == CENTRAL) { + // Compute the function on the other side of x(j). + x_plus_delta(j) = x(j) - delta; + + if (!EvaluateImpl( + functor, parameters, residuals, functor)) { + return false; + } + + parameter_jacobian.col(j) -= + Map(residuals, kNumResiduals, 1); + one_over_delta /= 2; + } else { + // Forward difference only; reuse existing residuals evaluation. + parameter_jacobian.col(j) -= + Map(residuals_at_eval_point, kNumResiduals); + } + x_plus_delta(j) = x(j); // Restore x_plus_delta. + + // Divide out the run to get slope. + parameter_jacobian.col(j) *= one_over_delta; + } + return true; + } +}; + +template +struct NumericDiff { + // Mutates parameters but must restore them before return. + static bool EvaluateJacobianForParameterBlock( + const CostFunctor* functor, + double const* residuals_at_eval_point, + const double relative_step_size, + double **parameters, + double *jacobian) { + LOG(FATAL) << "Control should never reach here."; + return true; + } +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_ diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h b/extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h index 44f198b339d..5dfb551243c 100644 --- a/extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h +++ b/extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h @@ -38,6 +38,7 @@ #include #include #include +#include namespace ceres { namespace internal { @@ -49,18 +50,17 @@ template class scoped_array; template scoped_ptr make_scoped_ptr(C *); -// A scoped_ptr is like a T*, except that the destructor of scoped_ptr -// automatically deletes the pointer it holds (if any). That is, scoped_ptr -// owns the T object that it points to. Like a T*, a scoped_ptr may hold -// either NULL or a pointer to a T object. Also like T*, scoped_ptr is -// thread-compatible, and once you dereference it, you get the threadsafety -// guarantees of T. +// A scoped_ptr is like a T*, except that the destructor of +// scoped_ptr automatically deletes the pointer it holds (if +// any). That is, scoped_ptr owns the T object that it points +// to. Like a T*, a scoped_ptr may hold either NULL or a pointer to +// a T object. Also like T*, scoped_ptr is thread-compatible, and +// once you dereference it, you get the threadsafety guarantees of T. // // The size of a scoped_ptr is small: sizeof(scoped_ptr) == sizeof(C*) template class scoped_ptr { public: - // The element type typedef C element_type; @@ -193,7 +193,6 @@ scoped_ptr make_scoped_ptr(C *p) { template class scoped_array { public: - // The element type typedef C element_type; diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/variadic_evaluate.h b/extern/libmv/third_party/ceres/include/ceres/internal/variadic_evaluate.h new file mode 100644 index 00000000000..4b1e4bdc65a --- /dev/null +++ b/extern/libmv/third_party/ceres/include/ceres/internal/variadic_evaluate.h @@ -0,0 +1,182 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2013 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) +// mierle@gmail.com (Keir Mierle) + +#ifndef CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_ +#define CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_ + +#include + +#include +#include "ceres/jet.h" +#include "ceres/internal/eigen.h" +#include "ceres/internal/fixed_array.h" + +namespace ceres { +namespace internal { + +// This block of quasi-repeated code calls the user-supplied functor, which may +// take a variable number of arguments. This is accomplished by specializing the +// struct based on the size of the trailing parameters; parameters with 0 size +// are assumed missing. +template +struct VariadicEvaluate { + static bool Call(const Functor& functor, T const *const *input, T* output) { + return functor(input[0], + input[1], + input[2], + input[3], + input[4], + input[5], + input[6], + input[7], + input[8], + input[9], + output); + } +}; + +template +struct VariadicEvaluate { + static bool Call(const Functor& functor, T const *const *input, T* output) { + return functor(input[0], + input[1], + input[2], + input[3], + input[4], + input[5], + input[6], + input[7], + input[8], + output); + } +}; + +template +struct VariadicEvaluate { + static bool Call(const Functor& functor, T const *const *input, T* output) { + return functor(input[0], + input[1], + input[2], + input[3], + input[4], + input[5], + input[6], + input[7], + output); + } +}; + +template +struct VariadicEvaluate { + static bool Call(const Functor& functor, T const *const *input, T* output) { + return functor(input[0], + input[1], + input[2], + input[3], + input[4], + input[5], + input[6], + output); + } +}; + +template +struct VariadicEvaluate { + static bool Call(const Functor& functor, T const *const *input, T* output) { + return functor(input[0], + input[1], + input[2], + input[3], + input[4], + input[5], + output); + } +}; + +template +struct VariadicEvaluate { + static bool Call(const Functor& functor, T const *const *input, T* output) { + return functor(input[0], + input[1], + input[2], + input[3], + input[4], + output); + } +}; + +template +struct VariadicEvaluate { + static bool Call(const Functor& functor, T const *const *input, T* output) { + return functor(input[0], + input[1], + input[2], + input[3], + output); + } +}; + +template +struct VariadicEvaluate { + static bool Call(const Functor& functor, T const *const *input, T* output) { + return functor(input[0], + input[1], + input[2], + output); + } +}; + +template +struct VariadicEvaluate { + static bool Call(const Functor& functor, T const *const *input, T* output) { + return functor(input[0], + input[1], + output); + } +}; + +template +struct VariadicEvaluate { + static bool Call(const Functor& functor, T const *const *input, T* output) { + return functor(input[0], + output); + } +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_ diff --git a/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h b/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h index 29157d380f2..0dc4c96b441 100644 --- a/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h +++ b/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h @@ -42,6 +42,23 @@ namespace ceres { // This struct describes the state of the optimizer after each // iteration of the minimization. struct IterationSummary { + IterationSummary() + : iteration(0), + step_is_valid(false), + step_is_nonmonotonic(false), + step_is_successful(false), + cost(0.0), + cost_change(0.0), + gradient_max_norm(0.0), + step_norm(0.0), + eta(0.0), + step_size(0.0), + line_search_function_evaluations(0), + linear_solver_iterations(0), + iteration_time_in_seconds(0.0), + step_solver_time_in_seconds(0.0), + cumulative_time_in_seconds(0.0) {} + // Current iteration number. int32 iteration; @@ -51,7 +68,22 @@ struct IterationSummary { // Note: step_is_valid is false when iteration = 0. bool step_is_valid; - // Whether or not the algorithm made progress in this iteration. + // Step did not reduce the value of the objective function + // sufficiently, but it was accepted because of the relaxed + // acceptance criterion used by the non-monotonic trust region + // algorithm. + // + // Note: step_is_nonmonotonic is false when iteration = 0; + bool step_is_nonmonotonic; + + // Whether or not the minimizer accepted this step or not. If the + // ordinary trust region algorithm is used, this means that the + // relative reduction in the objective function value was greater + // than Solver::Options::min_relative_decrease. However, if the + // non-monotonic trust region algorithm is used + // (Solver::Options:use_nonmonotonic_steps = true), then even if the + // relative decrease is not sufficient, the algorithm may accept the + // step and the step is declared successful. // // Note: step_is_successful is false when iteration = 0. bool step_is_successful; @@ -60,8 +92,7 @@ struct IterationSummary { double cost; // Change in the value of the objective function in this - // iteration. This can be positive or negative. Negative change - // means that the step was not successful. + // iteration. This can be positive or negative. double cost_change; // Infinity norm of the gradient vector. @@ -87,6 +118,12 @@ struct IterationSummary { // ignore it. double eta; + // Step sized computed by the line search algorithm. + double step_size; + + // Number of function evaluations used by the line search algorithm. + int line_search_function_evaluations; + // Number of iterations taken by the linear solver to solve for the // Newton step. int linear_solver_iterations; diff --git a/extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h b/extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h index 8544e44d0bc..555bc3d073f 100644 --- a/extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h +++ b/extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h @@ -27,19 +27,109 @@ // POSSIBILITY OF SUCH DAMAGE. // // Author: keir@google.com (Keir Mierle) +// sameeragarwal@google.com (Sameer Agarwal) // // Create CostFunctions as needed by the least squares framework with jacobians // computed via numeric (a.k.a. finite) differentiation. For more details see // http://en.wikipedia.org/wiki/Numerical_differentiation. // -// To get a numerically differentiated cost function, define a subclass of -// CostFunction such that the Evaluate() function ignores the jacobian -// parameter. The numeric differentiation wrapper will fill in the jacobian -// parameter if nececssary by repeatedly calling the Evaluate() function with -// small changes to the appropriate parameters, and computing the slope. For -// performance, the numeric differentiation wrapper class is templated on the -// concrete cost function, even though it could be implemented only in terms of -// the virtual CostFunction interface. +// To get an numerically differentiated cost function, you must define +// a class with a operator() (a functor) that computes the residuals. +// +// The function must write the computed value in the last argument (the only +// non-const one) and return true to indicate success. +// +// For example, consider a scalar error e = k - x'y, where both x and y are +// two-dimensional column vector parameters, the prime sign indicates +// transposition, and k is a constant. The form of this error, which is the +// difference between a constant and an expression, is a common pattern in least +// squares problems. For example, the value x'y might be the model expectation +// for a series of measurements, where there is an instance of the cost function +// for each measurement k. +// +// The actual cost added to the total problem is e^2, or (k - x'k)^2; however, +// the squaring is implicitly done by the optimization framework. +// +// To write an numerically-differentiable cost function for the above model, first +// define the object +// +// class MyScalarCostFunctor { +// MyScalarCostFunctor(double k): k_(k) {} +// +// bool operator()(const double* const x, +// const double* const y, +// double* residuals) const { +// residuals[0] = k_ - x[0] * y[0] + x[1] * y[1]; +// return true; +// } +// +// private: +// double k_; +// }; +// +// Note that in the declaration of operator() the input parameters x +// and y come first, and are passed as const pointers to arrays of +// doubles. If there were three input parameters, then the third input +// parameter would come after y. The output is always the last +// parameter, and is also a pointer to an array. In the example above, +// the residual is a scalar, so only residuals[0] is set. +// +// Then given this class definition, the numerically differentiated +// cost function with central differences used for computing the +// derivative can be constructed as follows. +// +// CostFunction* cost_function +// = new NumericDiffCostFunction( +// new MyScalarCostFunctor(1.0)); ^ ^ ^ +// | | | | +// Finite Differencing Scheme -+ | | | +// Dimension of residual ----------+ | | +// Dimension of x --------------------+ | +// Dimension of y -----------------------+ +// +// In this example, there is usually an instance for each measumerent of k. +// +// In the instantiation above, the template parameters following +// "MyScalarCostFunctor", "1, 2, 2", describe the functor as computing +// a 1-dimensional output from two arguments, both 2-dimensional. +// +// The framework can currently accommodate cost functions of up to 10 +// independent variables, and there is no limit on the dimensionality +// of each of them. +// +// The central difference method is considerably more accurate at the cost of +// twice as many function evaluations than forward difference. Consider using +// central differences begin with, and only after that works, trying forward +// difference to improve performance. +// +// TODO(sameeragarwal): Add support for dynamic number of residuals. +// +// WARNING #1: A common beginner's error when first using +// NumericDiffCostFunction is to get the sizing wrong. In particular, +// there is a tendency to set the template parameters to (dimension of +// residual, number of parameters) instead of passing a dimension +// parameter for *every parameter*. In the example above, that would +// be , which is missing the last '2' +// argument. Please be careful when setting the size parameters. +// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +// +// ALTERNATE INTERFACE +// +// For a variety of reason, including compatibility with legacy code, +// NumericDiffCostFunction can also take CostFunction objects as +// input. The following describes how. +// +// To get a numerically differentiated cost function, define a +// subclass of CostFunction such that the Evaluate() function ignores +// the jacobian parameter. The numeric differentiation wrapper will +// fill in the jacobian parameter if nececssary by repeatedly calling +// the Evaluate() function with small changes to the appropriate +// parameters, and computing the slope. For performance, the numeric +// differentiation wrapper class is templated on the concrete cost +// function, even though it could be implemented only in terms of the +// virtual CostFunction interface. // // The numerically differentiated version of a cost function for a cost function // can be constructed as follows: @@ -51,233 +141,153 @@ // where MyCostFunction has 1 residual and 2 parameter blocks with sizes 4 and 8 // respectively. Look at the tests for a more detailed example. // -// The central difference method is considerably more accurate at the cost of -// twice as many function evaluations than forward difference. Consider using -// central differences begin with, and only after that works, trying forward -// difference to improve performance. -// // TODO(keir): Characterize accuracy; mention pitfalls; provide alternatives. #ifndef CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_ #define CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_ -#include #include #include "Eigen/Dense" +#include "ceres/cost_function.h" +#include "ceres/internal/numeric_diff.h" #include "ceres/internal/scoped_ptr.h" #include "ceres/sized_cost_function.h" #include "ceres/types.h" namespace ceres { -enum NumericDiffMethod { - CENTRAL, - FORWARD -}; - -// This is split from the main class because C++ doesn't allow partial template -// specializations for member functions. The alternative is to repeat the main -// class for differing numbers of parameters, which is also unfortunate. -template -struct Differencer { - // Mutates parameters but must restore them before return. - static bool EvaluateJacobianForParameterBlock( - const CostFunctionNoJacobian *function, - double const* residuals_at_eval_point, - double **parameters, - double **jacobians) { - using Eigen::Map; - using Eigen::Matrix; - using Eigen::RowMajor; - using Eigen::ColMajor; - - typedef Matrix ResidualVector; - typedef Matrix ParameterVector; - typedef Matrix 1) ? ColMajor : RowMajor> JacobianMatrix; - - Map parameter_jacobian(jacobians[parameter_block], - num_residuals, - parameter_block_size); - - // Mutate 1 element at a time and then restore. - Map x_plus_delta(parameters[parameter_block], - parameter_block_size); - ParameterVector x(x_plus_delta); - - // TODO(keir): Pick a smarter number! In theory a good choice is sqrt(eps) * - // x, which for doubles means about 1e-8 * x. However, I have found this - // number too optimistic. This number should be exposed for users to change. - const double kRelativeStepSize = 1e-6; - - ParameterVector step_size = x.array().abs() * kRelativeStepSize; - - // To handle cases where a parameter is exactly zero, instead use the mean - // step_size for the other dimensions. - double fallback_step_size = step_size.sum() / step_size.rows(); - if (fallback_step_size == 0.0) { - // If all the parameters are zero, there's no good answer. Take - // kRelativeStepSize as a guess and hope for the best. - fallback_step_size = kRelativeStepSize; - } - - // For each parameter in the parameter block, use finite differences to - // compute the derivative for that parameter. - for (int j = 0; j < parameter_block_size; ++j) { - if (step_size(j) == 0.0) { - // The parameter is exactly zero, so compromise and use the mean - // step_size from the other parameters. This can break in many cases, - // but it's hard to pick a good number without problem specific - // knowledge. - step_size(j) = fallback_step_size; - } - x_plus_delta(j) = x(j) + step_size(j); - - double residuals[num_residuals]; // NOLINT - if (!function->Evaluate(parameters, residuals, NULL)) { - // Something went wrong; bail. - return false; - } - - // Compute this column of the jacobian in 3 steps: - // 1. Store residuals for the forward part. - // 2. Subtract residuals for the backward (or 0) part. - // 3. Divide out the run. - parameter_jacobian.col(j) = - Map(residuals, num_residuals); - - double one_over_h = 1 / step_size(j); - if (method == CENTRAL) { - // Compute the function on the other side of x(j). - x_plus_delta(j) = x(j) - step_size(j); - - if (!function->Evaluate(parameters, residuals, NULL)) { - // Something went wrong; bail. - return false; - } - parameter_jacobian.col(j) -= - Map(residuals, num_residuals, 1); - one_over_h /= 2; - } else { - // Forward difference only; reuse existing residuals evaluation. - parameter_jacobian.col(j) -= - Map(residuals_at_eval_point, num_residuals); - } - x_plus_delta(j) = x(j); // Restore x_plus_delta. - - // Divide out the run to get slope. - parameter_jacobian.col(j) *= one_over_h; - } - return true; - } -}; - -// Prevent invalid instantiations. -template -struct Differencer { - static bool EvaluateJacobianForParameterBlock( - const CostFunctionNoJacobian *function, - double const* residuals_at_eval_point, - double **parameters, - double **jacobians) { - LOG(FATAL) << "Shouldn't get here."; - return true; - } -}; - -template +template // Number of parameters in block 9. class NumericDiffCostFunction - : public SizedCostFunction { + : public SizedCostFunction { public: - NumericDiffCostFunction(CostFunctionNoJacobian* function, - Ownership ownership) - : function_(function), ownership_(ownership) {} + NumericDiffCostFunction(CostFunctor* functor, + const double relative_step_size = 1e-6) + :functor_(functor), + ownership_(TAKE_OWNERSHIP), + relative_step_size_(relative_step_size) {} - virtual ~NumericDiffCostFunction() { + NumericDiffCostFunction(CostFunctor* functor, + Ownership ownership, + const double relative_step_size = 1e-6) + : functor_(functor), + ownership_(ownership), + relative_step_size_(relative_step_size) {} + + ~NumericDiffCostFunction() { if (ownership_ != TAKE_OWNERSHIP) { - function_.release(); + functor_.release(); } } virtual bool Evaluate(double const* const* parameters, double* residuals, double** jacobians) const { + using internal::FixedArray; + using internal::NumericDiff; + + const int kNumParameters = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9; + const int kNumParameterBlocks = + (N0 > 0) + (N1 > 0) + (N2 > 0) + (N3 > 0) + (N4 > 0) + + (N5 > 0) + (N6 > 0) + (N7 > 0) + (N8 > 0) + (N9 > 0); + // Get the function value (residuals) at the the point to evaluate. - bool success = function_->Evaluate(parameters, residuals, NULL); - if (!success) { - // Something went wrong; ignore the jacobian. + if (!internal::EvaluateImpl( + functor_.get(), + parameters, + residuals, + functor_.get())) { return false; } + if (!jacobians) { - // Nothing to do; just forward. return true; } // Create a copy of the parameters which will get mutated. - const int kParametersSize = N0 + N1 + N2 + N3 + N4 + N5; - double parameters_copy[kParametersSize]; - double *parameters_references_copy[6]; - parameters_references_copy[0] = ¶meters_copy[0]; - parameters_references_copy[1] = ¶meters_copy[0] + N0; - parameters_references_copy[2] = ¶meters_copy[0] + N0 + N1; - parameters_references_copy[3] = ¶meters_copy[0] + N0 + N1 + N2; - parameters_references_copy[4] = ¶meters_copy[0] + N0 + N1 + N2 + N3; - parameters_references_copy[5] = - ¶meters_copy[0] + N0 + N1 + N2 + N3 + N4; + FixedArray parameters_copy(kNumParameters); + FixedArray parameters_reference_copy(kNumParameterBlocks); + + parameters_reference_copy[0] = parameters_copy.get(); + if (N1) parameters_reference_copy[1] = parameters_reference_copy[0] + N0; + if (N2) parameters_reference_copy[2] = parameters_reference_copy[1] + N1; + if (N3) parameters_reference_copy[3] = parameters_reference_copy[2] + N2; + if (N4) parameters_reference_copy[4] = parameters_reference_copy[3] + N3; + if (N5) parameters_reference_copy[5] = parameters_reference_copy[4] + N4; + if (N6) parameters_reference_copy[6] = parameters_reference_copy[5] + N5; + if (N7) parameters_reference_copy[7] = parameters_reference_copy[6] + N6; + if (N7) parameters_reference_copy[8] = parameters_reference_copy[7] + N7; + if (N8) parameters_reference_copy[9] = parameters_reference_copy[8] + N8; + +#define COPY_PARAMETER_BLOCK(block) \ + if (N ## block) memcpy(parameters_reference_copy[block], \ + parameters[block], \ + sizeof(double) * N ## block); // NOLINT -#define COPY_PARAMETER_BLOCK(block) \ - if (N ## block) memcpy(parameters_references_copy[block], \ - parameters[block], \ - sizeof(double) * N ## block); // NOLINT COPY_PARAMETER_BLOCK(0); COPY_PARAMETER_BLOCK(1); COPY_PARAMETER_BLOCK(2); COPY_PARAMETER_BLOCK(3); COPY_PARAMETER_BLOCK(4); COPY_PARAMETER_BLOCK(5); + COPY_PARAMETER_BLOCK(6); + COPY_PARAMETER_BLOCK(7); + COPY_PARAMETER_BLOCK(8); + COPY_PARAMETER_BLOCK(9); + #undef COPY_PARAMETER_BLOCK -#define EVALUATE_JACOBIAN_FOR_BLOCK(block) \ - if (N ## block && jacobians[block]) { \ - if (!Differencer::EvaluateJacobianForParameterBlock( \ - function_.get(), \ - residuals, \ - parameters_references_copy, \ - jacobians)) { \ - return false; \ - } \ +#define EVALUATE_JACOBIAN_FOR_BLOCK(block) \ + if (N ## block && jacobians[block] != NULL) { \ + if (!NumericDiff::EvaluateJacobianForParameterBlock( \ + functor_.get(), \ + residuals, \ + relative_step_size_, \ + parameters_reference_copy.get(), \ + jacobians[block])) { \ + return false; \ + } \ } + EVALUATE_JACOBIAN_FOR_BLOCK(0); EVALUATE_JACOBIAN_FOR_BLOCK(1); EVALUATE_JACOBIAN_FOR_BLOCK(2); EVALUATE_JACOBIAN_FOR_BLOCK(3); EVALUATE_JACOBIAN_FOR_BLOCK(4); EVALUATE_JACOBIAN_FOR_BLOCK(5); + EVALUATE_JACOBIAN_FOR_BLOCK(6); + EVALUATE_JACOBIAN_FOR_BLOCK(7); + EVALUATE_JACOBIAN_FOR_BLOCK(8); + EVALUATE_JACOBIAN_FOR_BLOCK(9); + #undef EVALUATE_JACOBIAN_FOR_BLOCK + return true; } private: - internal::scoped_ptr function_; + internal::scoped_ptr functor_; Ownership ownership_; + const double relative_step_size_; }; } // namespace ceres diff --git a/extern/libmv/third_party/ceres/include/ceres/numeric_diff_functor.h b/extern/libmv/third_party/ceres/include/ceres/numeric_diff_functor.h new file mode 100644 index 00000000000..593c3718bf5 --- /dev/null +++ b/extern/libmv/third_party/ceres/include/ceres/numeric_diff_functor.h @@ -0,0 +1,346 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2013 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) +// +// A wrapper class that takes a variadic functor evaluating a +// function, numerically differentiates it and makes it available as a +// templated functor so that it can be easily used as part of Ceres' +// automatic differentiation framework. +// +// For example: +// +// For example, let us assume that +// +// struct IntrinsicProjection +// IntrinsicProjection(const double* observations); +// bool operator()(const double* calibration, +// const double* point, +// double* residuals); +// }; +// +// is a functor that implements the projection of a point in its local +// coordinate system onto its image plane and subtracts it from the +// observed point projection. +// +// Now we would like to compose the action of this functor with the +// action of camera extrinsics, i.e., rotation and translation, which +// is given by the following templated function +// +// template +// void RotateAndTranslatePoint(const T* rotation, +// const T* translation, +// const T* point, +// T* result); +// +// To compose the extrinsics and intrinsics, we can construct a +// CameraProjection functor as follows. +// +// struct CameraProjection { +// typedef NumericDiffFunctor +// IntrinsicProjectionFunctor; +// +// CameraProjection(double* observation) { +// intrinsic_projection_.reset( +// new IntrinsicProjectionFunctor(observation)) { +// } +// +// template +// bool operator(const T* rotation, +// const T* translation, +// const T* intrinsics, +// const T* point, +// T* residuals) const { +// T transformed_point[3]; +// RotateAndTranslatePoint(rotation, translation, point, transformed_point); +// return (*intrinsic_projection_)(intrinsics, transformed_point, residual); +// } +// +// private: +// scoped_ptr intrinsic_projection_; +// }; +// +// Here, we made the choice of using CENTRAL differences to compute +// the jacobian of IntrinsicProjection. +// +// Now, we are ready to construct an automatically differentiated cost +// function as +// +// CostFunction* cost_function = +// new AutoDiffCostFunction( +// new CameraProjection(observations)); +// +// cost_function now seamlessly integrates automatic differentiation +// of RotateAndTranslatePoint with a numerically differentiated +// version of IntrinsicProjection. + +#ifndef CERES_PUBLIC_NUMERIC_DIFF_FUNCTOR_H_ +#define CERES_PUBLIC_NUMERIC_DIFF_FUNCTOR_H_ + +#include "ceres/numeric_diff_cost_function.h" +#include "ceres/types.h" +#include "ceres/cost_function_to_functor.h" + +namespace ceres { + +template +class NumericDiffFunctor { + public: + // relative_step_size controls the step size used by the numeric + // differentiation process. + explicit NumericDiffFunctor(double relative_step_size = 1e-6) + : functor_( + new NumericDiffCostFunction(new Functor, + relative_step_size)) { + } + + NumericDiffFunctor(Functor* functor, double relative_step_size = 1e-6) + : functor_(new NumericDiffCostFunction( + functor, relative_step_size)) { + } + + bool operator()(const double* x0, double* residuals) const { + return functor_(x0, residuals); + } + + bool operator()(const double* x0, + const double* x1, + double* residuals) const { + return functor_(x0, x1, residuals); + } + + bool operator()(const double* x0, + const double* x1, + const double* x2, + double* residuals) const { + return functor_(x0, x1, x2, residuals); + } + + bool operator()(const double* x0, + const double* x1, + const double* x2, + const double* x3, + double* residuals) const { + return functor_(x0, x1, x2, x3, residuals); + } + + bool operator()(const double* x0, + const double* x1, + const double* x2, + const double* x3, + const double* x4, + double* residuals) const { + return functor_(x0, x1, x2, x3, x4, residuals); + } + + bool operator()(const double* x0, + const double* x1, + const double* x2, + const double* x3, + const double* x4, + const double* x5, + double* residuals) const { + return functor_(x0, x1, x2, x3, x4, x5, residuals); + } + + bool operator()(const double* x0, + const double* x1, + const double* x2, + const double* x3, + const double* x4, + const double* x5, + const double* x6, + double* residuals) const { + return functor_(x0, x1, x2, x3, x4, x5, x6, residuals); + } + + bool operator()(const double* x0, + const double* x1, + const double* x2, + const double* x3, + const double* x4, + const double* x5, + const double* x6, + const double* x7, + double* residuals) const { + return functor_(x0, x1, x2, x3, x4, x5, x6, x7, residuals); + } + + bool operator()(const double* x0, + const double* x1, + const double* x2, + const double* x3, + const double* x4, + const double* x5, + const double* x6, + const double* x7, + const double* x8, + double* residuals) const { + return functor_(x0, x1, x2, x3, x4, x5, x6, x7, x8, residuals); + } + + bool operator()(const double* x0, + const double* x1, + const double* x2, + const double* x3, + const double* x4, + const double* x5, + const double* x6, + const double* x7, + const double* x8, + const double* x9, + double* residuals) const { + return functor_(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, residuals); + } + + template + bool operator()(const T* x0, T* residuals) const { + return functor_(x0, residuals); + } + + template + bool operator()(const T* x0, + const T* x1, + T* residuals) const { + return functor_(x0, x1, residuals); + } + + template + bool operator()(const T* x0, + const T* x1, + const T* x2, + T* residuals) const { + return functor_(x0, x1, x2, residuals); + } + + template + bool operator()(const T* x0, + const T* x1, + const T* x2, + const T* x3, + T* residuals) const { + return functor_(x0, x1, x2, x3, residuals); + } + + template + bool operator()(const T* x0, + const T* x1, + const T* x2, + const T* x3, + const T* x4, + T* residuals) const { + return functor_(x0, x1, x2, x3, x4, residuals); + } + + template + bool operator()(const T* x0, + const T* x1, + const T* x2, + const T* x3, + const T* x4, + const T* x5, + T* residuals) const { + return functor_(x0, x1, x2, x3, x4, x5, residuals); + } + + template + bool operator()(const T* x0, + const T* x1, + const T* x2, + const T* x3, + const T* x4, + const T* x5, + const T* x6, + T* residuals) const { + return functor_(x0, x1, x2, x3, x4, x5, x6, residuals); + } + + template + bool operator()(const T* x0, + const T* x1, + const T* x2, + const T* x3, + const T* x4, + const T* x5, + const T* x6, + const T* x7, + T* residuals) const { + return functor_(x0, x1, x2, x3, x4, x5, x6, x7, residuals); + } + + template + bool operator()(const T* x0, + const T* x1, + const T* x2, + const T* x3, + const T* x4, + const T* x5, + const T* x6, + const T* x7, + const T* x8, + T* residuals) const { + return functor_(x0, x1, x2, x3, x4, x5, x6, x7, x8, residuals); + } + + template + bool operator()(const T* x0, + const T* x1, + const T* x2, + const T* x3, + const T* x4, + const T* x5, + const T* x6, + const T* x7, + const T* x8, + const T* x9, + T* residuals) const { + return functor_(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, residuals); + } + + + private: + CostFunctionToFunctor functor_; +}; + +} // namespace ceres + +#endif // CERES_PUBLIC_NUMERIC_DIFF_FUNCTOR_H_ diff --git a/extern/libmv/third_party/ceres/include/ceres/ordered_groups.h b/extern/libmv/third_party/ceres/include/ceres/ordered_groups.h new file mode 100644 index 00000000000..e373d35b9d7 --- /dev/null +++ b/extern/libmv/third_party/ceres/include/ceres/ordered_groups.h @@ -0,0 +1,176 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#ifndef CERES_PUBLIC_ORDERED_GROUPS_H_ +#define CERES_PUBLIC_ORDERED_GROUPS_H_ + +#include +#include +#include "ceres/internal/port.h" + +namespace ceres { + +// A class for storing and manipulating an ordered collection of +// groups/sets with the following semantics: +// +// Group ids are non-negative integer values. Elements are any type +// that can serve as a key in a map or an element of a set. +// +// An element can only belong to one group at a time. A group may +// contain an arbitrary number of elements. +// +// Groups are ordered by their group id. +template +class OrderedGroups { + public: + // Add an element to a group. If a group with this id does not + // exist, one is created. This method can be called any number of + // times for the same element. Group ids should be non-negative + // numbers. + // + // Return value indicates if adding the element was a success. + bool AddElementToGroup(const T element, const int group) { + if (group < 0) { + return false; + } + + typename map::const_iterator it = element_to_group_.find(element); + if (it != element_to_group_.end()) { + if (it->second == group) { + // Element is already in the right group, nothing to do. + return true; + } + + group_to_elements_[it->second].erase(element); + if (group_to_elements_[it->second].size() == 0) { + group_to_elements_.erase(it->second); + } + } + + element_to_group_[element] = group; + group_to_elements_[group].insert(element); + return true; + } + + void Clear() { + group_to_elements_.clear(); + element_to_group_.clear(); + } + + // Remove the element, no matter what group it is in. If the element + // is not a member of any group, calling this method will result in + // a crash. + // + // Return value indicates if the element was actually removed. + bool Remove(const T element) { + const int current_group = GroupId(element); + if (current_group < 0) { + return false; + } + + group_to_elements_[current_group].erase(element); + + if (group_to_elements_[current_group].size() == 0) { + // If the group is empty, then get rid of it. + group_to_elements_.erase(current_group); + } + + element_to_group_.erase(element); + return true; + } + + // Reverse the order of the groups in place. + void Reverse() { + typename map >::reverse_iterator it = + group_to_elements_.rbegin(); + map > new_group_to_elements; + new_group_to_elements[it->first] = it->second; + + int new_group_id = it->first + 1; + for (++it; it != group_to_elements_.rend(); ++it) { + for (typename set::const_iterator element_it = it->second.begin(); + element_it != it->second.end(); + ++element_it) { + element_to_group_[*element_it] = new_group_id; + } + new_group_to_elements[new_group_id] = it->second; + new_group_id++; + } + + group_to_elements_.swap(new_group_to_elements); + } + + // Return the group id for the element. If the element is not a + // member of any group, return -1. + int GroupId(const T element) const { + typename map::const_iterator it = element_to_group_.find(element); + if (it == element_to_group_.end()) { + return -1; + } + return it->second; + } + + bool IsMember(const T element) const { + typename map::const_iterator it = element_to_group_.find(element); + return (it != element_to_group_.end()); + } + + // This function always succeeds, i.e., implicitly there exists a + // group for every integer. + int GroupSize(const int group) const { + typename map >::const_iterator it = + group_to_elements_.find(group); + return (it == group_to_elements_.end()) ? 0 : it->second.size(); + } + + int NumElements() const { + return element_to_group_.size(); + } + + // Number of groups with one or more elements. + int NumGroups() const { + return group_to_elements_.size(); + } + + const map >& group_to_elements() const { + return group_to_elements_; + } + + private: + map > group_to_elements_; + map element_to_group_; +}; + +// Typedef for the most commonly used version of OrderedGroups. +typedef OrderedGroups ParameterBlockOrdering; + +} // namespace ceres + +#endif // CERES_PUBLIC_ORDERED_GROUP_H_ diff --git a/extern/libmv/third_party/ceres/include/ceres/problem.h b/extern/libmv/third_party/ceres/include/ceres/problem.h index 2b08c6723e8..bccb329dc55 100644 --- a/extern/libmv/third_party/ceres/include/ceres/problem.h +++ b/extern/libmv/third_party/ceres/include/ceres/problem.h @@ -39,11 +39,12 @@ #include #include -#include #include "ceres/internal/macros.h" #include "ceres/internal/port.h" #include "ceres/internal/scoped_ptr.h" #include "ceres/types.h" +#include "glog/logging.h" + namespace ceres { @@ -51,6 +52,7 @@ class CostFunction; class LossFunction; class LocalParameterization; class Solver; +struct CRSMatrix; namespace internal { class Preprocessor; @@ -59,10 +61,9 @@ class ParameterBlock; class ResidualBlock; } // namespace internal -// A ResidualBlockId is a handle clients can use to delete residual -// blocks after creating them. They are opaque for any purposes other -// than that. -typedef const internal::ResidualBlock* ResidualBlockId; +// A ResidualBlockId is an opaque handle clients can use to remove residual +// blocks from a Problem after adding them. +typedef internal::ResidualBlock* ResidualBlockId; // A class to represent non-linear least squares problems. Such // problems have a cost function that is a sum of error terms (known @@ -122,7 +123,9 @@ class Problem { Options() : cost_function_ownership(TAKE_OWNERSHIP), loss_function_ownership(TAKE_OWNERSHIP), - local_parameterization_ownership(TAKE_OWNERSHIP) {} + local_parameterization_ownership(TAKE_OWNERSHIP), + enable_fast_parameter_block_removal(false), + disable_all_safety_checks(false) {} // These flags control whether the Problem object owns the cost // functions, loss functions, and parameterizations passed into @@ -134,6 +137,29 @@ class Problem { Ownership cost_function_ownership; Ownership loss_function_ownership; Ownership local_parameterization_ownership; + + // If true, trades memory for a faster RemoveParameterBlock() operation. + // + // RemoveParameterBlock() takes time proportional to the size of the entire + // Problem. If you only remove parameter blocks from the Problem + // occassionaly, this may be acceptable. However, if you are modifying the + // Problem frequently, and have memory to spare, then flip this switch to + // make RemoveParameterBlock() take time proportional to the number of + // residual blocks that depend on it. The increase in memory usage is an + // additonal hash set per parameter block containing all the residuals that + // depend on the parameter block. + bool enable_fast_parameter_block_removal; + + // By default, Ceres performs a variety of safety checks when constructing + // the problem. There is a small but measurable performance penalty to + // these checks, typically around 5% of construction time. If you are sure + // your problem construction is correct, and 5% of the problem construction + // time is truly an overhead you want to avoid, then you can set + // disable_all_safety_checks to true. + // + // WARNING: Do not set this to true, unless you are absolutely sure of what + // you are doing. + bool disable_all_safety_checks; }; // The default constructor is equivalent to the @@ -208,6 +234,27 @@ class Problem { LossFunction* loss_function, double* x0, double* x1, double* x2, double* x3, double* x4, double* x5); + ResidualBlockId AddResidualBlock(CostFunction* cost_function, + LossFunction* loss_function, + double* x0, double* x1, double* x2, + double* x3, double* x4, double* x5, + double* x6); + ResidualBlockId AddResidualBlock(CostFunction* cost_function, + LossFunction* loss_function, + double* x0, double* x1, double* x2, + double* x3, double* x4, double* x5, + double* x6, double* x7); + ResidualBlockId AddResidualBlock(CostFunction* cost_function, + LossFunction* loss_function, + double* x0, double* x1, double* x2, + double* x3, double* x4, double* x5, + double* x6, double* x7, double* x8); + ResidualBlockId AddResidualBlock(CostFunction* cost_function, + LossFunction* loss_function, + double* x0, double* x1, double* x2, + double* x3, double* x4, double* x5, + double* x6, double* x7, double* x8, + double* x9); // Add a parameter block with appropriate size to the problem. // Repeated calls with the same arguments are ignored. Repeated @@ -223,6 +270,33 @@ class Problem { int size, LocalParameterization* local_parameterization); + // Remove a parameter block from the problem. The parameterization of the + // parameter block, if it exists, will persist until the deletion of the + // problem (similar to cost/loss functions in residual block removal). Any + // residual blocks that depend on the parameter are also removed, as + // described above in RemoveResidualBlock(). + // + // If Problem::Options::enable_fast_parameter_block_removal is true, then the + // removal is fast (almost constant time). Otherwise, removing a parameter + // block will incur a scan of the entire Problem object. + // + // WARNING: Removing a residual or parameter block will destroy the implicit + // ordering, rendering the jacobian or residuals returned from the solver + // uninterpretable. If you depend on the evaluated jacobian, do not use + // remove! This may change in a future release. + void RemoveParameterBlock(double* values); + + // Remove a residual block from the problem. Any parameters that the residual + // block depends on are not removed. The cost and loss functions for the + // residual block will not get deleted immediately; won't happen until the + // problem itself is deleted. + // + // WARNING: Removing a residual or parameter block will destroy the implicit + // ordering, rendering the jacobian or residuals returned from the solver + // uninterpretable. If you depend on the evaluated jacobian, do not use + // remove! This may change in a future release. + void RemoveResidualBlock(ResidualBlockId residual_block); + // Hold the indicated parameter block constant during optimization. void SetParameterBlockConstant(double* values); @@ -254,6 +328,76 @@ class Problem { // sizes of all of the residual blocks. int NumResiduals() const; + // Options struct to control Problem::Evaluate. + struct EvaluateOptions { + EvaluateOptions() + : num_threads(1) { + } + + // The set of parameter blocks for which evaluation should be + // performed. This vector determines the order that parameter + // blocks occur in the gradient vector and in the columns of the + // jacobian matrix. If parameter_blocks is empty, then it is + // assumed to be equal to vector containing ALL the parameter + // blocks. Generally speaking the parameter blocks will occur in + // the order in which they were added to the problem. But, this + // may change if the user removes any parameter blocks from the + // problem. + // + // NOTE: This vector should contain the same pointers as the ones + // used to add parameter blocks to the Problem. These parmeter + // block should NOT point to new memory locations. Bad things will + // happen otherwise. + vector parameter_blocks; + + // The set of residual blocks to evaluate. This vector determines + // the order in which the residuals occur, and how the rows of the + // jacobian are ordered. If residual_blocks is empty, then it is + // assumed to be equal to the vector containing all the residual + // blocks. If this vector is empty, then it is assumed to be equal + // to a vector containing ALL the residual blocks. Generally + // speaking the residual blocks will occur in the order in which + // they were added to the problem. But, this may change if the + // user removes any residual blocks from the problem. + vector residual_blocks; + int num_threads; + }; + + // Evaluate Problem. Any of the output pointers can be NULL. Which + // residual blocks and parameter blocks are used is controlled by + // the EvaluateOptions struct above. + // + // Note 1: The evaluation will use the values stored in the memory + // locations pointed to by the parameter block pointers used at the + // time of the construction of the problem. i.e., + // + // Problem problem; + // double x = 1; + // problem.Add(new MyCostFunction, NULL, &x); + // + // double cost = 0.0; + // problem.Evaluate(Problem::EvaluateOptions(), &cost, NULL, NULL, NULL); + // + // The cost is evaluated at x = 1. If you wish to evaluate the + // problem at x = 2, then + // + // x = 2; + // problem.Evaluate(Problem::EvaluateOptions(), &cost, NULL, NULL, NULL); + // + // is the way to do so. + // + // Note 2: If no local parameterizations are used, then the size of + // the gradient vector (and the number of columns in the jacobian) + // is the sum of the sizes of all the parameter blocks. If a + // parameter block has a local parameterization, then it contributes + // "LocalSize" entries to the gradient vecto (and the number of + // columns in the jacobian). + bool Evaluate(const EvaluateOptions& options, + double* cost, + vector* residuals, + vector* gradient, + CRSMatrix* jacobian); + private: friend class Solver; internal::scoped_ptr problem_impl_; diff --git a/extern/libmv/third_party/ceres/include/ceres/rotation.h b/extern/libmv/third_party/ceres/include/ceres/rotation.h index 0d8a390d5d1..ffac4f1dc0c 100644 --- a/extern/libmv/third_party/ceres/include/ceres/rotation.h +++ b/extern/libmv/third_party/ceres/include/ceres/rotation.h @@ -51,6 +51,31 @@ namespace ceres { +// Trivial wrapper to index linear arrays as matrices, given a fixed +// column and row stride. When an array "T* array" is wrapped by a +// +// (const) MatrixAdapter M" +// +// the expression M(i, j) is equivalent to +// +// arrary[i * row_stride + j * col_stride] +// +// Conversion functions to and from rotation matrices accept +// MatrixAdapters to permit using row-major and column-major layouts, +// and rotation matrices embedded in larger matrices (such as a 3x4 +// projection matrix). +template +struct MatrixAdapter; + +// Convenience functions to create a MatrixAdapter that treats the +// array pointed to by "pointer" as a 3x3 (contiguous) column-major or +// row-major matrix. +template +MatrixAdapter ColumnMajorAdapter3x3(T* pointer); + +template +MatrixAdapter RowMajorAdapter3x3(T* pointer); + // Convert a value in combined axis-angle representation to a quaternion. // The value angle_axis is a triple whose norm is an angle in radians, // and whose direction is aligned with the axis of rotation, @@ -73,9 +98,20 @@ void QuaternionToAngleAxis(T const* quaternion, T* angle_axis); // axis-angle rotation representations. Templated for use with // autodifferentiation. template -void RotationMatrixToAngleAxis(T const * R, T * angle_axis); +void RotationMatrixToAngleAxis(T const* R, T* angle_axis); + +template +void RotationMatrixToAngleAxis( + const MatrixAdapter& R, + T* angle_axis); + template -void AngleAxisToRotationMatrix(T const * angle_axis, T * R); +void AngleAxisToRotationMatrix(T const* angle_axis, T* R); + +template +void AngleAxisToRotationMatrix( + T const* angle_axis, + const MatrixAdapter& R); // Conversions between 3x3 rotation matrix (in row major order) and // Euler angle (in degrees) rotation representations. @@ -86,6 +122,11 @@ void AngleAxisToRotationMatrix(T const * angle_axis, T * R); template void EulerAnglesToRotationMatrix(const T* euler, int row_stride, T* R); +template +void EulerAnglesToRotationMatrix( + const T* euler, + const MatrixAdapter& R); + // Convert a 4-vector to a 3x3 scaled rotation matrix. // // The choice of rotation is such that the quaternion [1 0 0 0] goes to an @@ -108,11 +149,21 @@ void EulerAnglesToRotationMatrix(const T* euler, int row_stride, T* R); template inline void QuaternionToScaledRotation(const T q[4], T R[3 * 3]); +template inline +void QuaternionToScaledRotation( + const T q[4], + const MatrixAdapter& R); + // Same as above except that the rotation matrix is normalized by the // Frobenius norm, so that R * R' = I (and det(R) = 1). template inline void QuaternionToRotation(const T q[4], T R[3 * 3]); +template inline +void QuaternionToRotation( + const T q[4], + const MatrixAdapter& R); + // Rotates a point pt by a quaternion q: // // result = R(q) * pt @@ -146,6 +197,28 @@ void AngleAxisRotatePoint(const T angle_axis[3], const T pt[3], T result[3]); // --- IMPLEMENTATION +template +struct MatrixAdapter { + T* pointer_; + explicit MatrixAdapter(T* pointer) + : pointer_(pointer) + {} + + T& operator()(int r, int c) const { + return pointer_[r * row_stride + c * col_stride]; + } +}; + +template +MatrixAdapter ColumnMajorAdapter3x3(T* pointer) { + return MatrixAdapter(pointer); +} + +template +MatrixAdapter RowMajorAdapter3x3(T* pointer) { + return MatrixAdapter(pointer); +} + template inline void AngleAxisToQuaternion(const T* angle_axis, T* quaternion) { const T& a0 = angle_axis[0]; @@ -228,17 +301,24 @@ inline void QuaternionToAngleAxis(const T* quaternion, T* angle_axis) { // to not perform division by a small number. template inline void RotationMatrixToAngleAxis(const T * R, T * angle_axis) { + RotationMatrixToAngleAxis(ColumnMajorAdapter3x3(R), angle_axis); +} + +template +void RotationMatrixToAngleAxis( + const MatrixAdapter& R, + T * angle_axis) { // x = k * 2 * sin(theta), where k is the axis of rotation. - angle_axis[0] = R[5] - R[7]; - angle_axis[1] = R[6] - R[2]; - angle_axis[2] = R[1] - R[3]; + angle_axis[0] = R(2, 1) - R(1, 2); + angle_axis[1] = R(0, 2) - R(2, 0); + angle_axis[2] = R(1, 0) - R(0, 1); static const T kOne = T(1.0); static const T kTwo = T(2.0); // Since the right hand side may give numbers just above 1.0 or // below -1.0 leading to atan misbehaving, we threshold. - T costheta = std::min(std::max((R[0] + R[4] + R[8] - kOne) / kTwo, + T costheta = std::min(std::max((R(0, 0) + R(1, 1) + R(2, 2) - kOne) / kTwo, T(-1.0)), kOne); @@ -296,7 +376,7 @@ inline void RotationMatrixToAngleAxis(const T * R, T * angle_axis) { // with the sign of sin(theta). If they are the same, then // angle_axis[i] should be positive, otherwise negative. for (int i = 0; i < 3; ++i) { - angle_axis[i] = theta * sqrt((R[i*4] - costheta) * inv_one_minus_costheta); + angle_axis[i] = theta * sqrt((R(i, i) - costheta) * inv_one_minus_costheta); if (((sintheta < 0.0) && (angle_axis[i] > 0.0)) || ((sintheta > 0.0) && (angle_axis[i] < 0.0))) { angle_axis[i] = -angle_axis[i]; @@ -306,6 +386,13 @@ inline void RotationMatrixToAngleAxis(const T * R, T * angle_axis) { template inline void AngleAxisToRotationMatrix(const T * angle_axis, T * R) { + AngleAxisToRotationMatrix(angle_axis, ColumnMajorAdapter3x3(R)); +} + +template +void AngleAxisToRotationMatrix( + const T * angle_axis, + const MatrixAdapter& R) { static const T kOne = T(1.0); const T theta2 = DotProduct(angle_axis, angle_axis); if (theta2 > 0.0) { @@ -320,33 +407,41 @@ inline void AngleAxisToRotationMatrix(const T * angle_axis, T * R) { const T costheta = cos(theta); const T sintheta = sin(theta); - R[0] = costheta + wx*wx*(kOne - costheta); - R[1] = wz*sintheta + wx*wy*(kOne - costheta); - R[2] = -wy*sintheta + wx*wz*(kOne - costheta); - R[3] = wx*wy*(kOne - costheta) - wz*sintheta; - R[4] = costheta + wy*wy*(kOne - costheta); - R[5] = wx*sintheta + wy*wz*(kOne - costheta); - R[6] = wy*sintheta + wx*wz*(kOne - costheta); - R[7] = -wx*sintheta + wy*wz*(kOne - costheta); - R[8] = costheta + wz*wz*(kOne - costheta); + R(0, 0) = costheta + wx*wx*(kOne - costheta); + R(1, 0) = wz*sintheta + wx*wy*(kOne - costheta); + R(2, 0) = -wy*sintheta + wx*wz*(kOne - costheta); + R(0, 1) = wx*wy*(kOne - costheta) - wz*sintheta; + R(1, 1) = costheta + wy*wy*(kOne - costheta); + R(2, 1) = wx*sintheta + wy*wz*(kOne - costheta); + R(0, 2) = wy*sintheta + wx*wz*(kOne - costheta); + R(1, 2) = -wx*sintheta + wy*wz*(kOne - costheta); + R(2, 2) = costheta + wz*wz*(kOne - costheta); } else { // At zero, we switch to using the first order Taylor expansion. - R[0] = kOne; - R[1] = -angle_axis[2]; - R[2] = angle_axis[1]; - R[3] = angle_axis[2]; - R[4] = kOne; - R[5] = -angle_axis[0]; - R[6] = -angle_axis[1]; - R[7] = angle_axis[0]; - R[8] = kOne; + R(0, 0) = kOne; + R(1, 0) = -angle_axis[2]; + R(2, 0) = angle_axis[1]; + R(0, 1) = angle_axis[2]; + R(1, 1) = kOne; + R(2, 1) = -angle_axis[0]; + R(0, 2) = -angle_axis[1]; + R(1, 2) = angle_axis[0]; + R(2, 2) = kOne; } } template inline void EulerAnglesToRotationMatrix(const T* euler, - const int row_stride, + const int row_stride_parameter, T* R) { + CHECK_EQ(row_stride_parameter, 3); + EulerAnglesToRotationMatrix(euler, RowMajorAdapter3x3(R)); +} + +template +void EulerAnglesToRotationMatrix( + const T* euler, + const MatrixAdapter& R) { const double kPi = 3.14159265358979323846; const T degrees_to_radians(kPi / 180.0); @@ -361,26 +456,28 @@ inline void EulerAnglesToRotationMatrix(const T* euler, const T c3 = cos(pitch); const T s3 = sin(pitch); - // Rows of the rotation matrix. - T* R1 = R; - T* R2 = R1 + row_stride; - T* R3 = R2 + row_stride; - - R1[0] = c1*c2; - R1[1] = -s1*c3 + c1*s2*s3; - R1[2] = s1*s3 + c1*s2*c3; + R(0, 0) = c1*c2; + R(0, 1) = -s1*c3 + c1*s2*s3; + R(0, 2) = s1*s3 + c1*s2*c3; - R2[0] = s1*c2; - R2[1] = c1*c3 + s1*s2*s3; - R2[2] = -c1*s3 + s1*s2*c3; + R(1, 0) = s1*c2; + R(1, 1) = c1*c3 + s1*s2*s3; + R(1, 2) = -c1*s3 + s1*s2*c3; - R3[0] = -s2; - R3[1] = c2*s3; - R3[2] = c2*c3; + R(2, 0) = -s2; + R(2, 1) = c2*s3; + R(2, 2) = c2*c3; } template inline void QuaternionToScaledRotation(const T q[4], T R[3 * 3]) { + QuaternionToScaledRotation(q, RowMajorAdapter3x3(R)); +} + +template inline +void QuaternionToScaledRotation( + const T q[4], + const MatrixAdapter& R) { // Make convenient names for elements of q. T a = q[0]; T b = q[1]; @@ -399,21 +496,29 @@ void QuaternionToScaledRotation(const T q[4], T R[3 * 3]) { T cd = c * d; T dd = d * d; - R[0] = aa + bb - cc - dd; R[1] = T(2) * (bc - ad); R[2] = T(2) * (ac + bd); // NOLINT - R[3] = T(2) * (ad + bc); R[4] = aa - bb + cc - dd; R[5] = T(2) * (cd - ab); // NOLINT - R[6] = T(2) * (bd - ac); R[7] = T(2) * (ab + cd); R[8] = aa - bb - cc + dd; // NOLINT + R(0, 0) = aa + bb - cc - dd; R(0, 1) = T(2) * (bc - ad); R(0, 2) = T(2) * (ac + bd); // NOLINT + R(1, 0) = T(2) * (ad + bc); R(1, 1) = aa - bb + cc - dd; R(1, 2) = T(2) * (cd - ab); // NOLINT + R(2, 0) = T(2) * (bd - ac); R(2, 1) = T(2) * (ab + cd); R(2, 2) = aa - bb - cc + dd; // NOLINT } template inline void QuaternionToRotation(const T q[4], T R[3 * 3]) { + QuaternionToRotation(q, RowMajorAdapter3x3(R)); +} + +template inline +void QuaternionToRotation(const T q[4], + const MatrixAdapter& R) { QuaternionToScaledRotation(q, R); T normalizer = q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]; CHECK_NE(normalizer, T(0)); normalizer = T(1) / normalizer; - for (int i = 0; i < 9; ++i) { - R[i] *= normalizer; + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + R(i, j) *= normalizer; + } } } @@ -433,7 +538,6 @@ void UnitQuaternionRotatePoint(const T q[4], const T pt[3], T result[3]) { result[2] = T(2) * ((t7 - t3) * pt[0] + (t2 + t9) * pt[1] + (t5 + t8) * pt[2]) + pt[2]; // NOLINT } - template inline void QuaternionRotatePoint(const T q[4], const T pt[3], T result[3]) { // 'scale' is 1 / norm(q). diff --git a/extern/libmv/third_party/ceres/include/ceres/sized_cost_function.h b/extern/libmv/third_party/ceres/include/ceres/sized_cost_function.h index 2894a9fba5c..6bfc1af31a2 100644 --- a/extern/libmv/third_party/ceres/include/ceres/sized_cost_function.h +++ b/extern/libmv/third_party/ceres/include/ceres/sized_cost_function.h @@ -45,25 +45,29 @@ namespace ceres { template + int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0, + int N5 = 0, int N6 = 0, int N7 = 0, int N8 = 0, int N9 = 0> class SizedCostFunction : public CostFunction { public: SizedCostFunction() { - // Sanity checking. CHECK(kNumResiduals > 0 || kNumResiduals == DYNAMIC) << "Cost functions must have at least one residual block."; - CHECK_GT(N0, 0) - << "Cost functions must have at least one parameter block."; - CHECK((!N1 && !N2 && !N3 && !N4 && !N5) || - ((N1 > 0) && !N2 && !N3 && !N4 && !N5) || - ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5) || - ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5) || - ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5) || - ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0))) + // This block breaks the 80 column rule to keep it somewhat readable. + CHECK((!N1 && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5 && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && !N6 && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && !N7 && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && !N8 && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && !N9) || + ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && (N9 > 0))) << "Zero block cannot precede a non-zero block. Block sizes are " << "(ignore trailing 0s): " << N0 << ", " << N1 << ", " << N2 << ", " - << N3 << ", " << N4 << ", " << N5; + << N3 << ", " << N4 << ", " << N5 << ", " << N6 << ", " << N7 << ", " + << N8 << ", " << N9; set_num_residuals(kNumResiduals); @@ -75,6 +79,10 @@ class SizedCostFunction : public CostFunction { ADD_PARAMETER_BLOCK(N3); ADD_PARAMETER_BLOCK(N4); ADD_PARAMETER_BLOCK(N5); + ADD_PARAMETER_BLOCK(N6); + ADD_PARAMETER_BLOCK(N7); + ADD_PARAMETER_BLOCK(N8); + ADD_PARAMETER_BLOCK(N9); #undef ADD_PARAMETER_BLOCK } diff --git a/extern/libmv/third_party/ceres/include/ceres/solver.h b/extern/libmv/third_party/ceres/include/ceres/solver.h index 31d5e8d7987..122870c86c8 100644 --- a/extern/libmv/third_party/ceres/include/ceres/solver.h +++ b/extern/libmv/third_party/ceres/include/ceres/solver.h @@ -38,6 +38,7 @@ #include "ceres/internal/macros.h" #include "ceres/internal/port.h" #include "ceres/iteration_callback.h" +#include "ceres/ordered_groups.h" #include "ceres/types.h" namespace ceres { @@ -57,6 +58,11 @@ class Solver { struct Options { // Default constructor that sets up a generic sparse problem. Options() { + minimizer_type = TRUST_REGION; + line_search_direction_type = LBFGS; + line_search_type = ARMIJO; + nonlinear_conjugate_gradient_type = FLETCHER_REEVES; + max_lbfgs_rank = 20; trust_region_strategy_type = LEVENBERG_MARQUARDT; dogleg_type = TRADITIONAL_DOGLEG; use_nonmonotonic_steps = false; @@ -89,27 +95,21 @@ class Solver { #endif num_linear_solver_threads = 1; - num_eliminate_blocks = 0; - ordering_type = NATURAL; #if defined(CERES_NO_SUITESPARSE) use_block_amd = false; #else use_block_amd = true; #endif - + linear_solver_ordering = NULL; + use_inner_iterations = false; + inner_iteration_ordering = NULL; linear_solver_min_num_iterations = 1; linear_solver_max_num_iterations = 500; eta = 1e-1; jacobi_scaling = true; logging_type = PER_MINIMIZER_ITERATION; minimizer_progress_to_stdout = false; - return_initial_residuals = false; - return_initial_gradient = false; - return_initial_jacobian = false; - return_final_residuals = false; - return_final_gradient = false; - return_final_jacobian = false; lsqp_dump_directory = "/tmp"; lsqp_dump_format_type = TEXTFILE; check_gradients = false; @@ -118,8 +118,64 @@ class Solver { update_state_every_iteration = false; } + ~Options(); // Minimizer options ---------------------------------------- + // Ceres supports the two major families of optimization strategies - + // Trust Region and Line Search. + // + // 1. The line search approach first finds a descent direction + // along which the objective function will be reduced and then + // computes a step size that decides how far should move along + // that direction. The descent direction can be computed by + // various methods, such as gradient descent, Newton's method and + // Quasi-Newton method. The step size can be determined either + // exactly or inexactly. + // + // 2. The trust region approach approximates the objective + // function using using a model function (often a quadratic) over + // a subset of the search space known as the trust region. If the + // model function succeeds in minimizing the true objective + // function the trust region is expanded; conversely, otherwise it + // is contracted and the model optimization problem is solved + // again. + // + // Trust region methods are in some sense dual to line search methods: + // trust region methods first choose a step size (the size of the + // trust region) and then a step direction while line search methods + // first choose a step direction and then a step size. + MinimizerType minimizer_type; + + LineSearchDirectionType line_search_direction_type; + LineSearchType line_search_type; + NonlinearConjugateGradientType nonlinear_conjugate_gradient_type; + + // The LBFGS hessian approximation is a low rank approximation to + // the inverse of the Hessian matrix. The rank of the + // approximation determines (linearly) the space and time + // complexity of using the approximation. Higher the rank, the + // better is the quality of the approximation. The increase in + // quality is however is bounded for a number of reasons. + // + // 1. The method only uses secant information and not actual + // derivatives. + // + // 2. The Hessian approximation is constrained to be positive + // definite. + // + // So increasing this rank to a large number will cost time and + // space complexity without the corresponding increase in solution + // quality. There are no hard and fast rules for choosing the + // maximum rank. The best choice usually requires some problem + // specific experimentation. + // + // For more theoretical and implementation details of the LBFGS + // method, please see: + // + // Nocedal, J. (1980). "Updating Quasi-Newton Matrices with + // Limited Storage". Mathematics of Computation 35 (151): 773–782. + int max_lbfgs_rank; + TrustRegionStrategyType trust_region_strategy_type; // Type of dogleg strategy to use. @@ -229,29 +285,76 @@ class Solver { // using this setting. int num_linear_solver_threads; - // For Schur reduction based methods, the first 0 to num blocks are - // eliminated using the Schur reduction. For example, when solving - // traditional structure from motion problems where the parameters are in - // two classes (cameras and points) then num_eliminate_blocks would be the - // number of points. - // - // This parameter is used in conjunction with the ordering. - // Applies to: Preprocessor and linear least squares solver. - int num_eliminate_blocks; - - // Internally Ceres reorders the parameter blocks to help the - // various linear solvers. This parameter allows the user to - // influence the re-ordering strategy used. For structure from - // motion problems use SCHUR, for other problems NATURAL (default) - // is a good choice. In case you wish to specify your own ordering - // scheme, for example in conjunction with num_eliminate_blocks, - // use USER. - OrderingType ordering_type; - - // The ordering of the parameter blocks. The solver pays attention - // to it if the ordering_type is set to USER and the vector is - // non-empty. - vector ordering; + // The order in which variables are eliminated in a linear solver + // can have a significant of impact on the efficiency and accuracy + // of the method. e.g., when doing sparse Cholesky factorization, + // there are matrices for which a good ordering will give a + // Cholesky factor with O(n) storage, where as a bad ordering will + // result in an completely dense factor. + // + // Ceres allows the user to provide varying amounts of hints to + // the solver about the variable elimination ordering to use. This + // can range from no hints, where the solver is free to decide the + // best possible ordering based on the user's choices like the + // linear solver being used, to an exact order in which the + // variables should be eliminated, and a variety of possibilities + // in between. + // + // Instances of the ParameterBlockOrdering class are used to + // communicate this information to Ceres. + // + // Formally an ordering is an ordered partitioning of the + // parameter blocks, i.e, each parameter block belongs to exactly + // one group, and each group has a unique non-negative integer + // associated with it, that determines its order in the set of + // groups. + // + // Given such an ordering, Ceres ensures that the parameter blocks in + // the lowest numbered group are eliminated first, and then the + // parmeter blocks in the next lowest numbered group and so on. Within + // each group, Ceres is free to order the parameter blocks as it + // chooses. + // + // If NULL, then all parameter blocks are assumed to be in the + // same group and the solver is free to decide the best + // ordering. + // + // e.g. Consider the linear system + // + // x + y = 3 + // 2x + 3y = 7 + // + // There are two ways in which it can be solved. First eliminating x + // from the two equations, solving for y and then back substituting + // for x, or first eliminating y, solving for x and back substituting + // for y. The user can construct three orderings here. + // + // {0: x}, {1: y} - eliminate x first. + // {0: y}, {1: x} - eliminate y first. + // {0: x, y} - Solver gets to decide the elimination order. + // + // Thus, to have Ceres determine the ordering automatically using + // heuristics, put all the variables in group 0 and to control the + // ordering for every variable, create groups 0..N-1, one per + // variable, in the desired order. + // + // Bundle Adjustment + // ----------------- + // + // A particular case of interest is bundle adjustment, where the user + // has two options. The default is to not specify an ordering at all, + // the solver will see that the user wants to use a Schur type solver + // and figure out the right elimination ordering. + // + // But if the user already knows what parameter blocks are points and + // what are cameras, they can save preprocessing time by partitioning + // the parameter blocks into two groups, one for the points and one + // for the cameras, where the group containing the points has an id + // smaller than the group containing cameras. + // + // Once assigned, Solver::Options owns this pointer and will + // deallocate the memory when destroyed. + ParameterBlockOrdering* linear_solver_ordering; // By virtue of the modeling layer in Ceres being block oriented, // all the matrices used by Ceres are also block oriented. When @@ -267,6 +370,77 @@ class Solver { // sparse_linear_algebra_library = SUITE_SPARSE. bool use_block_amd; + // Some non-linear least squares problems have additional + // structure in the way the parameter blocks interact that it is + // beneficial to modify the way the trust region step is computed. + // + // e.g., consider the following regression problem + // + // y = a_1 exp(b_1 x) + a_2 exp(b_3 x^2 + c_1) + // + // Given a set of pairs{(x_i, y_i)}, the user wishes to estimate + // a_1, a_2, b_1, b_2, and c_1. + // + // Notice here that the expression on the left is linear in a_1 + // and a_2, and given any value for b_1, b_2 and c_1, it is + // possible to use linear regression to estimate the optimal + // values of a_1 and a_2. Indeed, its possible to analytically + // eliminate the variables a_1 and a_2 from the problem all + // together. Problems like these are known as separable least + // squares problem and the most famous algorithm for solving them + // is the Variable Projection algorithm invented by Golub & + // Pereyra. + // + // Similar structure can be found in the matrix factorization with + // missing data problem. There the corresponding algorithm is + // known as Wiberg's algorithm. + // + // Ruhe & Wedin (Algorithms for Separable Nonlinear Least Squares + // Problems, SIAM Reviews, 22(3), 1980) present an analyis of + // various algorithms for solving separable non-linear least + // squares problems and refer to "Variable Projection" as + // Algorithm I in their paper. + // + // Implementing Variable Projection is tedious and expensive, and + // they present a simpler algorithm, which they refer to as + // Algorithm II, where once the Newton/Trust Region step has been + // computed for the whole problem (a_1, a_2, b_1, b_2, c_1) and + // additional optimization step is performed to estimate a_1 and + // a_2 exactly. + // + // This idea can be generalized to cases where the residual is not + // linear in a_1 and a_2, i.e., Solve for the trust region step + // for the full problem, and then use it as the starting point to + // further optimize just a_1 and a_2. For the linear case, this + // amounts to doing a single linear least squares solve. For + // non-linear problems, any method for solving the a_1 and a_2 + // optimization problems will do. The only constraint on a_1 and + // a_2 is that they do not co-occur in any residual block. + // + // This idea can be further generalized, by not just optimizing + // (a_1, a_2), but decomposing the graph corresponding to the + // Hessian matrix's sparsity structure in a collection of + // non-overlapping independent sets and optimizing each of them. + // + // Setting "use_inner_iterations" to true enables the use of this + // non-linear generalization of Ruhe & Wedin's Algorithm II. This + // version of Ceres has a higher iteration complexity, but also + // displays better convergence behaviour per iteration. Setting + // Solver::Options::num_threads to the maximum number possible is + // highly recommended. + bool use_inner_iterations; + + // If inner_iterations is true, then the user has two choices. + // + // 1. Let the solver heuristically decide which parameter blocks + // to optimize in each inner iteration. To do this leave + // Solver::Options::inner_iteration_ordering untouched. + // + // 2. Specify a collection of of ordered independent sets. Where + // the lower numbered groups are optimized before the higher + // number groups. Each group must be an independent set. + ParameterBlockOrdering* inner_iteration_ordering; + // Minimum number of iterations for which the linear solver should // run, even if the convergence criterion is satisfied. int linear_solver_min_num_iterations; @@ -301,14 +475,6 @@ class Solver { // is sent to STDOUT. bool minimizer_progress_to_stdout; - bool return_initial_residuals; - bool return_initial_gradient; - bool return_initial_jacobian; - - bool return_final_residuals; - bool return_final_gradient; - bool return_final_jacobian; - // List of iterations at which the optimizer should dump the // linear least squares problem to disk. Useful for testing and // benchmarking. If empty (default), no problems are dumped. @@ -398,6 +564,8 @@ class Solver { string FullReport() const; // Minimizer summary ------------------------------------------------- + MinimizerType minimizer_type; + SolverTerminationType termination_type; // If the solver did not run, or there was a failure, a @@ -414,54 +582,6 @@ class Solver { // blocks that they depend on were fixed. double fixed_cost; - // Vectors of residuals before and after the optimization. The - // entries of these vectors are in the order in which - // ResidualBlocks were added to the Problem object. - // - // Whether the residual vectors are populated with values is - // controlled by Solver::Options::return_initial_residuals and - // Solver::Options::return_final_residuals respectively. - vector initial_residuals; - vector final_residuals; - - // Gradient vectors, before and after the optimization. The rows - // are in the same order in which the ParameterBlocks were added - // to the Problem object. - // - // NOTE: Since AddResidualBlock adds ParameterBlocks to the - // Problem automatically if they do not already exist, if you wish - // to have explicit control over the ordering of the vectors, then - // use Problem::AddParameterBlock to explicitly add the - // ParameterBlocks in the order desired. - // - // Whether the vectors are populated with values is controlled by - // Solver::Options::return_initial_gradient and - // Solver::Options::return_final_gradient respectively. - vector initial_gradient; - vector final_gradient; - - // Jacobian matrices before and after the optimization. The rows - // of these matrices are in the same order in which the - // ResidualBlocks were added to the Problem object. The columns - // are in the same order in which the ParameterBlocks were added - // to the Problem object. - // - // NOTE: Since AddResidualBlock adds ParameterBlocks to the - // Problem automatically if they do not already exist, if you wish - // to have explicit control over the column ordering of the - // matrix, then use Problem::AddParameterBlock to explicitly add - // the ParameterBlocks in the order desired. - // - // The Jacobian matrices are stored as compressed row sparse - // matrices. Please see ceres/crs_matrix.h for more details of the - // format. - // - // Whether the Jacboan matrices are populated with values is - // controlled by Solver::Options::return_initial_jacobian and - // Solver::Options::return_final_jacobian respectively. - CRSMatrix initial_jacobian; - CRSMatrix final_jacobian; - vector iterations; int num_successful_steps; @@ -484,6 +604,10 @@ class Solver { // Some total of all time spent inside Ceres when Solve is called. double total_time_in_seconds; + double linear_solver_time_in_seconds; + double residual_evaluation_time_in_seconds; + double jacobian_evaluation_time_in_seconds; + // Preprocessor summary. int num_parameter_blocks; int num_parameters; @@ -507,12 +631,23 @@ class Solver { LinearSolverType linear_solver_type_given; LinearSolverType linear_solver_type_used; + vector linear_solver_ordering_given; + vector linear_solver_ordering_used; + PreconditionerType preconditioner_type; - OrderingType ordering_type; TrustRegionStrategyType trust_region_strategy_type; DoglegType dogleg_type; + bool inner_iterations; + SparseLinearAlgebraLibraryType sparse_linear_algebra_library; + + LineSearchDirectionType line_search_direction_type; + LineSearchType line_search_type; + int max_lbfgs_rank; + + vector inner_iteration_ordering_given; + vector inner_iteration_ordering_used; }; // Once a least squares problem has been built, this function takes diff --git a/extern/libmv/third_party/ceres/include/ceres/types.h b/extern/libmv/third_party/ceres/include/ceres/types.h index 3980885b53c..5512340f7b3 100644 --- a/extern/libmv/third_party/ceres/include/ceres/types.h +++ b/extern/libmv/third_party/ceres/include/ceres/types.h @@ -37,6 +37,8 @@ #ifndef CERES_PUBLIC_TYPES_H_ #define CERES_PUBLIC_TYPES_H_ +#include "ceres/internal/port.h" + namespace ceres { // Basic integer types. These typedefs are in the Ceres namespace to avoid @@ -99,8 +101,7 @@ enum PreconditionerType { JACOBI, // Block diagonal of the Schur complement. This preconditioner may - // only be used with the ITERATIVE_SCHUR solver. Requires - // SuiteSparse/CHOLMOD. + // only be used with the ITERATIVE_SCHUR solver. SCHUR_JACOBI, // Visibility clustering based preconditioners. @@ -143,18 +144,6 @@ enum LinearSolverTerminationType { FAILURE }; -enum OrderingType { - // The order in which the parameter blocks were defined. - NATURAL, - - // Use the ordering specificed in the vector ordering. - USER, - - // Automatically figure out the best ordering to use the schur - // complement based solver. - SCHUR -}; - // Logging options // The options get progressively noisier. enum LoggingType { @@ -162,6 +151,55 @@ enum LoggingType { PER_MINIMIZER_ITERATION }; +enum MinimizerType { + LINE_SEARCH, + TRUST_REGION +}; + +enum LineSearchDirectionType { + // Negative of the gradient. + STEEPEST_DESCENT, + + // A generalization of the Conjugate Gradient method to non-linear + // functions. The generalization can be performed in a number of + // different ways, resulting in a variety of search directions. The + // precise choice of the non-linear conjugate gradient algorithm + // used is determined by NonlinerConjuateGradientType. + NONLINEAR_CONJUGATE_GRADIENT, + + // A limited memory approximation to the inverse Hessian is + // maintained and used to compute a quasi-Newton step. + // + // For more details see + // + // Nocedal, J. (1980). "Updating Quasi-Newton Matrices with Limited + // Storage". Mathematics of Computation 35 (151): 773–782. + // + // Byrd, R. H.; Nocedal, J.; Schnabel, R. B. (1994). + // "Representations of Quasi-Newton Matrices and their use in + // Limited Memory Methods". Mathematical Programming 63 (4): + // 129–156. + LBFGS, +}; + +// Nonliner conjugate gradient methods are a generalization of the +// method of Conjugate Gradients for linear systems. The +// generalization can be carried out in a number of different ways +// leading to number of different rules for computing the search +// direction. Ceres provides a number of different variants. For more +// details see Numerical Optimization by Nocedal & Wright. +enum NonlinearConjugateGradientType { + FLETCHER_REEVES, + POLAK_RIBIRERE, + HESTENES_STIEFEL, +}; + +enum LineSearchType { + // Backtracking line search with polynomial interpolation or + // bisection. + ARMIJO, +}; + // Ceres supports different strategies for computing the trust region // step. enum TrustRegionStrategyType { @@ -296,18 +334,54 @@ enum DimensionType { DYNAMIC = -1 }; +enum NumericDiffMethod { + CENTRAL, + FORWARD +}; + const char* LinearSolverTypeToString(LinearSolverType type); +bool StringToLinearSolverType(string value, LinearSolverType* type); + const char* PreconditionerTypeToString(PreconditionerType type); +bool StringToPreconditionerType(string value, PreconditionerType* type); + const char* SparseLinearAlgebraLibraryTypeToString( SparseLinearAlgebraLibraryType type); +bool StringToSparseLinearAlgebraLibraryType( + string value, + SparseLinearAlgebraLibraryType* type); + +const char* TrustRegionStrategyTypeToString(TrustRegionStrategyType type); +bool StringToTrustRegionStrategyType(string value, + TrustRegionStrategyType* type); + +const char* DoglegTypeToString(DoglegType type); +bool StringToDoglegType(string value, DoglegType* type); + +const char* MinimizerTypeToString(MinimizerType type); +bool StringToMinimizerType(string value, MinimizerType* type); + +const char* LineSearchDirectionTypeToString(LineSearchDirectionType type); +bool StringToLineSearchDirectionType(string value, + LineSearchDirectionType* type); + +const char* LineSearchTypeToString(LineSearchType type); +bool StringToLineSearchType(string value, LineSearchType* type); + +const char* NonlinearConjugateGradientTypeToString( + NonlinearConjugateGradientType type); +bool StringToNonlinearConjugateGradientType( + string value, NonlinearConjugateGradientType* type); + const char* LinearSolverTerminationTypeToString( LinearSolverTerminationType type); -const char* OrderingTypeToString(OrderingType type); + const char* SolverTerminationTypeToString(SolverTerminationType type); -const char* SparseLinearAlgebraLibraryTypeToString( - SparseLinearAlgebraLibraryType type); -const char* TrustRegionStrategyTypeToString( TrustRegionStrategyType type); + bool IsSchurType(LinearSolverType type); +bool IsSparseLinearAlgebraLibraryTypeAvailable( + SparseLinearAlgebraLibraryType type); + } // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/array_utils.h b/extern/libmv/third_party/ceres/internal/ceres/array_utils.h index 99cc8d8ebbf..742f439d886 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/array_utils.h +++ b/extern/libmv/third_party/ceres/internal/ceres/array_utils.h @@ -28,7 +28,7 @@ // // Author: sameeragarwal@google.com (Sameer Agarwal) // -// Utility routines for validating arrays. +// Utility routines for validating arrays. // // These are useful for detecting two common class of errors. // diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc b/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc index 474c37f7ca4..1d5f9d77ab0 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc @@ -40,10 +40,10 @@ namespace ceres { namespace internal { -BlockJacobiPreconditioner::BlockJacobiPreconditioner(const LinearOperator& A) +BlockJacobiPreconditioner::BlockJacobiPreconditioner( + const BlockSparseMatrixBase& A) : num_rows_(A.num_rows()), - block_structure_( - *(down_cast(&A)->block_structure())) { + block_structure_(*A.block_structure()) { // Calculate the amount of storage needed. int storage_needed = 0; for (int c = 0; c < block_structure_.cols.size(); ++c) { @@ -64,11 +64,10 @@ BlockJacobiPreconditioner::BlockJacobiPreconditioner(const LinearOperator& A) } } -BlockJacobiPreconditioner::~BlockJacobiPreconditioner() { -} +BlockJacobiPreconditioner::~BlockJacobiPreconditioner() {} -void BlockJacobiPreconditioner::Update(const LinearOperator& matrix, const double* D) { - const BlockSparseMatrix& A = *(down_cast(&matrix)); +bool BlockJacobiPreconditioner::Update(const BlockSparseMatrixBase& A, + const double* D) { const CompressedRowBlockStructure* bs = A.block_structure(); // Compute the diagonal blocks by block inner products. @@ -107,16 +106,19 @@ void BlockJacobiPreconditioner::Update(const LinearOperator& matrix, const doubl MatrixRef block(blocks_[c], size, size); if (D != NULL) { - block.diagonal() += ConstVectorRef(D + position, size).array().square().matrix(); + block.diagonal() += + ConstVectorRef(D + position, size).array().square().matrix(); } block = block.selfadjointView() .ldlt() .solve(Matrix::Identity(size, size)); } + return true; } -void BlockJacobiPreconditioner::RightMultiply(const double* x, double* y) const { +void BlockJacobiPreconditioner::RightMultiply(const double* x, + double* y) const { for (int c = 0; c < block_structure_.cols.size(); ++c) { const int size = block_structure_.cols[c].size; const int position = block_structure_.cols[c].position; diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h b/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h index 91cfeddb688..ed5eebc8dc6 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h +++ b/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h @@ -32,38 +32,33 @@ #define CERES_INTERNAL_BLOCK_JACOBI_PRECONDITIONER_H_ #include -#include "ceres/linear_operator.h" +#include "ceres/preconditioner.h" namespace ceres { namespace internal { -class CompressedRowBlockStructure; +class BlockSparseMatrixBase; +struct CompressedRowBlockStructure; class LinearOperator; -class SparseMatrix; -// A block Jacobi preconditioner. This is intended for use with conjugate -// gradients, or other iterative symmetric solvers. To use the preconditioner, -// create one by passing a BlockSparseMatrix as the linear operator "A" to the -// constructor. This fixes the sparsity pattern to the pattern of the matrix -// A^TA. +// A block Jacobi preconditioner. This is intended for use with +// conjugate gradients, or other iterative symmetric solvers. To use +// the preconditioner, create one by passing a BlockSparseMatrix "A" +// to the constructor. This fixes the sparsity pattern to the pattern +// of the matrix A^TA. // // Before each use of the preconditioner in a solve with conjugate gradients, // update the matrix by running Update(A, D). The values of the matrix A are // inspected to construct the preconditioner. The vector D is applied as the // D^TD diagonal term. -class BlockJacobiPreconditioner : public LinearOperator { +class BlockJacobiPreconditioner : public Preconditioner { public: // A must remain valid while the BlockJacobiPreconditioner is. - BlockJacobiPreconditioner(const LinearOperator& A); + explicit BlockJacobiPreconditioner(const BlockSparseMatrixBase& A); virtual ~BlockJacobiPreconditioner(); - // Update the preconditioner with the values found in A. The sparsity pattern - // must match that of the A passed to the constructor. D is a vector that - // must have the same number of rows as A, and is applied as a diagonal in - // addition to the block diagonals of A. - void Update(const LinearOperator& A, const double* D); - - // LinearOperator interface. + // Preconditioner interface + virtual bool Update(const BlockSparseMatrixBase& A, const double* D); virtual void RightMultiply(const double* x, double* y) const; virtual void LeftMultiply(const double* x, double* y) const; virtual int num_rows() const { return num_rows_; } diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc index 0f95e8932b8..aedfc745f22 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc @@ -28,12 +28,12 @@ // // Author: sameeragarwal@google.com (Sameer Agarwal) -#include "glog/logging.h" #include "ceres/block_random_access_dense_matrix.h" #include #include "ceres/internal/eigen.h" #include "ceres/internal/scoped_ptr.h" +#include "glog/logging.h" namespace ceres { namespace internal { diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc index 9ed62ce948b..f789436364a 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc @@ -28,7 +28,6 @@ // // Author: sameeragarwal@google.com (Sameer Agarwal) -#include "glog/logging.h" #include "ceres/block_random_access_sparse_matrix.h" #include @@ -40,6 +39,7 @@ #include "ceres/mutex.h" #include "ceres/triplet_sparse_matrix.h" #include "ceres/types.h" +#include "glog/logging.h" namespace ceres { namespace internal { diff --git a/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h b/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h index 2d1eb403995..5f8e4e3e5dd 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h +++ b/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h @@ -43,16 +43,16 @@ #include -#include #include "ceres/collections_port.h" #include "ceres/graph.h" -#include "ceres/map_util.h" #include "ceres/internal/macros.h" +#include "ceres/map_util.h" +#include "glog/logging.h" namespace ceres { namespace internal { -class CanonicalViewsClusteringOptions; +struct CanonicalViewsClusteringOptions; // Compute a partitioning of the vertices of the graph using the // canonical views clustering algorithm. diff --git a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc index ccc8026f9f7..e2e799fe607 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc @@ -30,25 +30,28 @@ #include "ceres/cgnr_solver.h" -#include "glog/logging.h" -#include "ceres/linear_solver.h" +#include "ceres/block_jacobi_preconditioner.h" #include "ceres/cgnr_linear_operator.h" #include "ceres/conjugate_gradients_solver.h" -#include "ceres/block_jacobi_preconditioner.h" +#include "ceres/linear_solver.h" +#include "ceres/wall_time.h" +#include "glog/logging.h" namespace ceres { namespace internal { CgnrSolver::CgnrSolver(const LinearSolver::Options& options) : options_(options), - jacobi_preconditioner_(NULL) { + preconditioner_(NULL) { } -LinearSolver::Summary CgnrSolver::Solve( - LinearOperator* A, +LinearSolver::Summary CgnrSolver::SolveImpl( + BlockSparseMatrixBase* A, const double* b, const LinearSolver::PerSolveOptions& per_solve_options, double* x) { + EventLogger event_logger("CgnrSolver::Solve"); + // Form z = Atb. scoped_array z(new double[A->num_cols()]); std::fill(z.get(), z.get() + A->num_cols(), 0.0); @@ -57,11 +60,11 @@ LinearSolver::Summary CgnrSolver::Solve( // Precondition if necessary. LinearSolver::PerSolveOptions cg_per_solve_options = per_solve_options; if (options_.preconditioner_type == JACOBI) { - if (jacobi_preconditioner_.get() == NULL) { - jacobi_preconditioner_.reset(new BlockJacobiPreconditioner(*A)); + if (preconditioner_.get() == NULL) { + preconditioner_.reset(new BlockJacobiPreconditioner(*A)); } - jacobi_preconditioner_->Update(*A, per_solve_options.D); - cg_per_solve_options.preconditioner = jacobi_preconditioner_.get(); + preconditioner_->Update(*A, per_solve_options.D); + cg_per_solve_options.preconditioner = preconditioner_.get(); } else if (options_.preconditioner_type != IDENTITY) { LOG(FATAL) << "CGNR only supports IDENTITY and JACOBI preconditioners."; } @@ -69,11 +72,14 @@ LinearSolver::Summary CgnrSolver::Solve( // Solve (AtA + DtD)x = z (= Atb). std::fill(x, x + A->num_cols(), 0.0); CgnrLinearOperator lhs(*A, per_solve_options.D); + event_logger.AddEvent("Setup"); + ConjugateGradientsSolver conjugate_gradient_solver(options_); - return conjugate_gradient_solver.Solve(&lhs, - z.get(), - cg_per_solve_options, - x); + LinearSolver::Summary summary = + conjugate_gradient_solver.Solve(&lhs, z.get(), cg_per_solve_options, x); + event_logger.AddEvent("Solve"); + + return summary; } } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h b/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h index 877b4c4ceea..d560a9de58d 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h +++ b/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h @@ -37,6 +37,8 @@ namespace ceres { namespace internal { +class Preconditioner; + class BlockJacobiPreconditioner; // A conjugate gradients on the normal equations solver. This directly solves @@ -46,17 +48,18 @@ class BlockJacobiPreconditioner; // // as required for solving for x in the least squares sense. Currently only // block diagonal preconditioning is supported. -class CgnrSolver : public LinearSolver { +class CgnrSolver : public BlockSparseMatrixBaseSolver { public: explicit CgnrSolver(const LinearSolver::Options& options); - virtual Summary Solve(LinearOperator* A, - const double* b, - const LinearSolver::PerSolveOptions& per_solve_options, - double* x); + virtual Summary SolveImpl( + BlockSparseMatrixBase* A, + const double* b, + const LinearSolver::PerSolveOptions& per_solve_options, + double* x); private: const LinearSolver::Options options_; - scoped_ptr jacobi_preconditioner_; + scoped_ptr preconditioner_; CERES_DISALLOW_COPY_AND_ASSIGN(CgnrSolver); }; diff --git a/extern/libmv/third_party/ceres/internal/ceres/collections_port.h b/extern/libmv/third_party/ceres/internal/ceres/collections_port.h index c2fce9033cd..715c975e00e 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/collections_port.h +++ b/extern/libmv/third_party/ceres/internal/ceres/collections_port.h @@ -37,7 +37,7 @@ # include # include #else -# if defined(_MSC_VER) && _MSC_VER <= 1600 +# if defined(_MSC_VER) # include # include # else diff --git a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc index 912c4845441..bbadb772805 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc @@ -135,7 +135,8 @@ SparseMatrix* CompressedRowJacobianWriter::CreateJacobian() const { // Populate the row and column block vectors for use by block // oriented ordering algorithms. This is useful when // Solver::Options::use_block_amd = true. - const vector& parameter_blocks = program_->parameter_blocks(); + const vector& parameter_blocks = + program_->parameter_blocks(); vector& col_blocks = *(jacobian->mutable_col_blocks()); col_blocks.resize(parameter_blocks.size()); for (int i = 0; i < parameter_blocks.size(); ++i) { diff --git a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h index 6a9d82842e5..c9c904bf63c 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h +++ b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h @@ -32,17 +32,18 @@ #define CERES_INTERNAL_COMPRESSED_ROW_SPARSE_MATRIX_H_ #include -#include -#include "ceres/sparse_matrix.h" -#include "ceres/triplet_sparse_matrix.h" + #include "ceres/internal/eigen.h" #include "ceres/internal/macros.h" #include "ceres/internal/port.h" +#include "ceres/sparse_matrix.h" +#include "ceres/triplet_sparse_matrix.h" #include "ceres/types.h" +#include "glog/logging.h" namespace ceres { -class CRSMatrix; +struct CRSMatrix; namespace internal { diff --git a/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc b/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc new file mode 100644 index 00000000000..c4da987919a --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc @@ -0,0 +1,236 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#include "ceres/coordinate_descent_minimizer.h" + +#ifdef CERES_USE_OPENMP +#include +#endif + +#include +#include +#include +#include "ceres/evaluator.h" +#include "ceres/linear_solver.h" +#include "ceres/minimizer.h" +#include "ceres/ordered_groups.h" +#include "ceres/parameter_block.h" +#include "ceres/problem_impl.h" +#include "ceres/program.h" +#include "ceres/residual_block.h" +#include "ceres/solver.h" +#include "ceres/solver_impl.h" +#include "ceres/trust_region_minimizer.h" +#include "ceres/trust_region_strategy.h" + +namespace ceres { +namespace internal { + +CoordinateDescentMinimizer::~CoordinateDescentMinimizer() { +} + +bool CoordinateDescentMinimizer::Init( + const Program& program, + const ProblemImpl::ParameterMap& parameter_map, + const ParameterBlockOrdering& ordering, + string* error) { + parameter_blocks_.clear(); + independent_set_offsets_.clear(); + independent_set_offsets_.push_back(0); + + // Serialize the OrderedGroups into a vector of parameter block + // offsets for parallel access. + map parameter_block_index; + map > group_to_elements = ordering.group_to_elements(); + for (map >::const_iterator it = group_to_elements.begin(); + it != group_to_elements.end(); + ++it) { + for (set::const_iterator ptr_it = it->second.begin(); + ptr_it != it->second.end(); + ++ptr_it) { + parameter_blocks_.push_back(parameter_map.find(*ptr_it)->second); + parameter_block_index[parameter_blocks_.back()] = + parameter_blocks_.size() - 1; + } + independent_set_offsets_.push_back( + independent_set_offsets_.back() + it->second.size()); + } + + // The ordering does not have to contain all parameter blocks, so + // assign zero offsets/empty independent sets to these parameter + // blocks. + const vector& parameter_blocks = program.parameter_blocks(); + for (int i = 0; i < parameter_blocks.size(); ++i) { + if (!ordering.IsMember(parameter_blocks[i]->mutable_user_state())) { + parameter_blocks_.push_back(parameter_blocks[i]); + independent_set_offsets_.push_back(independent_set_offsets_.back()); + } + } + + // Compute the set of residual blocks that depend on each parameter + // block. + residual_blocks_.resize(parameter_block_index.size()); + const vector& residual_blocks = program.residual_blocks(); + for (int i = 0; i < residual_blocks.size(); ++i) { + ResidualBlock* residual_block = residual_blocks[i]; + const int num_parameter_blocks = residual_block->NumParameterBlocks(); + for (int j = 0; j < num_parameter_blocks; ++j) { + ParameterBlock* parameter_block = residual_block->parameter_blocks()[j]; + const map::const_iterator it = + parameter_block_index.find(parameter_block); + if (it != parameter_block_index.end()) { + residual_blocks_[it->second].push_back(residual_block); + } + } + } + + evaluator_options_.linear_solver_type = DENSE_QR; + evaluator_options_.num_eliminate_blocks = 0; + evaluator_options_.num_threads = 1; + + return true; +} + +void CoordinateDescentMinimizer::Minimize( + const Minimizer::Options& options, + double* parameters, + Solver::Summary* summary) { + // Set the state and mark all parameter blocks constant. + for (int i = 0; i < parameter_blocks_.size(); ++i) { + ParameterBlock* parameter_block = parameter_blocks_[i]; + parameter_block->SetState(parameters + parameter_block->state_offset()); + parameter_block->SetConstant(); + } + + scoped_array linear_solvers( + new LinearSolver*[options.num_threads]); + + LinearSolver::Options linear_solver_options; + linear_solver_options.type = DENSE_QR; + + for (int i = 0; i < options.num_threads; ++i) { + linear_solvers[i] = LinearSolver::Create(linear_solver_options); + } + + for (int i = 0; i < independent_set_offsets_.size() - 1; ++i) { + // No point paying the price for an OpemMP call if the set if of + // size zero. + if (independent_set_offsets_[i] == independent_set_offsets_[i + 1]) { + continue; + } + + // The parameter blocks in each independent set can be optimized + // in parallel, since they do not co-occur in any residual block. +#pragma omp parallel for num_threads(options.num_threads) + for (int j = independent_set_offsets_[i]; + j < independent_set_offsets_[i + 1]; + ++j) { +#ifdef CERES_USE_OPENMP + int thread_id = omp_get_thread_num(); +#else + int thread_id = 0; +#endif + + ParameterBlock* parameter_block = parameter_blocks_[j]; + const int old_index = parameter_block->index(); + const int old_delta_offset = parameter_block->delta_offset(); + parameter_block->SetVarying(); + parameter_block->set_index(0); + parameter_block->set_delta_offset(0); + + Program inner_program; + inner_program.mutable_parameter_blocks()->push_back(parameter_block); + *inner_program.mutable_residual_blocks() = residual_blocks_[j]; + + // TODO(sameeragarwal): Better error handling. Right now we + // assume that this is not going to lead to problems of any + // sort. Basically we should be checking for numerical failure + // of some sort. + // + // On the other hand, if the optimization is a failure, that in + // some ways is fine, since it won't change the parameters and + // we are fine. + Solver::Summary inner_summary; + Solve(&inner_program, + linear_solvers[thread_id], + parameters + parameter_block->state_offset(), + &inner_summary); + + parameter_block->set_index(old_index); + parameter_block->set_delta_offset(old_delta_offset); + parameter_block->SetState(parameters + parameter_block->state_offset()); + parameter_block->SetConstant(); + } + } + + for (int i = 0; i < parameter_blocks_.size(); ++i) { + parameter_blocks_[i]->SetVarying(); + } + + for (int i = 0; i < options.num_threads; ++i) { + delete linear_solvers[i]; + } +} + +// Solve the optimization problem for one parameter block. +void CoordinateDescentMinimizer::Solve(Program* program, + LinearSolver* linear_solver, + double* parameter, + Solver::Summary* summary) { + *summary = Solver::Summary(); + summary->initial_cost = 0.0; + summary->fixed_cost = 0.0; + summary->final_cost = 0.0; + string error; + + scoped_ptr evaluator( + Evaluator::Create(evaluator_options_, program, &error)); + CHECK_NOTNULL(evaluator.get()); + + scoped_ptr jacobian(evaluator->CreateJacobian()); + CHECK_NOTNULL(jacobian.get()); + + TrustRegionStrategy::Options trs_options; + trs_options.linear_solver = linear_solver; + + scoped_ptrtrust_region_strategy( + CHECK_NOTNULL(TrustRegionStrategy::Create(trs_options))); + + Minimizer::Options minimizer_options; + minimizer_options.evaluator = evaluator.get(); + minimizer_options.jacobian = jacobian.get(); + minimizer_options.trust_region_strategy = trust_region_strategy.get(); + + TrustRegionMinimizer minimizer; + minimizer.Minimize(minimizer_options, parameter, summary); +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h b/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h new file mode 100644 index 00000000000..3dcf8faee59 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h @@ -0,0 +1,88 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#ifndef CERES_INTERNAL_COORDINATE_DESCENT_MINIMIZER_H_ +#define CERES_INTERNAL_COORDINATE_DESCENT_MINIMIZER_H_ + +#include + +#include "ceres/evaluator.h" +#include "ceres/minimizer.h" +#include "ceres/problem_impl.h" +#include "ceres/program.h" +#include "ceres/solver.h" + +namespace ceres { +namespace internal { + +// Given a Program, and a ParameterBlockOrdering which partitions +// (non-exhaustively) the Hessian matrix into independent sets, +// perform coordinate descent on the parameter blocks in the +// ordering. The independent set structure allows for all parameter +// blocks in the same independent set to be optimized in parallel, and +// the order of the independent set determines the order in which the +// parameter block groups are optimized. +// +// The minimizer assumes that none of the parameter blocks in the +// program are constant. +class CoordinateDescentMinimizer : public Minimizer { + public: + bool Init(const Program& program, + const ProblemImpl::ParameterMap& parameter_map, + const ParameterBlockOrdering& ordering, + string* error); + + // Minimizer interface. + virtual ~CoordinateDescentMinimizer(); + virtual void Minimize(const Minimizer::Options& options, + double* parameters, + Solver::Summary* summary); + + private: + void Solve(Program* program, + LinearSolver* linear_solver, + double* parameters, + Solver::Summary* summary); + + vector parameter_blocks_; + vector > residual_blocks_; + // The optimization is performed in rounds. In each round all the + // parameter blocks that form one independent set are optimized in + // parallel. This array, marks the boundaries of the independent + // sets in parameter_blocks_. + vector independent_set_offsets_; + + Evaluator::Options evaluator_options_; +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_COORDINATE_DESCENT_MINIMIZER_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/corrector.cc b/extern/libmv/third_party/ceres/internal/ceres/corrector.cc index eff4dff8566..c3858abd2f4 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/corrector.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/corrector.cc @@ -113,12 +113,19 @@ void Corrector::CorrectJacobian(int nrow, int ncol, double* residuals, double* jacobian) { DCHECK(residuals != NULL); DCHECK(jacobian != NULL); - ConstVectorRef r_ref(residuals, nrow); - MatrixRef j_ref(jacobian, nrow, ncol); - // Equation 11 in BANS. - j_ref = sqrt_rho1_ * (j_ref - alpha_sq_norm_ * - r_ref * (r_ref.transpose() * j_ref)); + if (nrow == 1) { + // Specialization for the case where the residual is a scalar. + VectorRef j_ref(jacobian, ncol); + j_ref *= sqrt_rho1_ * (1.0 - alpha_sq_norm_ * pow(*residuals, 2)); + } else { + ConstVectorRef r_ref(residuals, nrow); + MatrixRef j_ref(jacobian, nrow, ncol); + + // Equation 11 in BANS. + j_ref = sqrt_rho1_ * (j_ref - alpha_sq_norm_ * + r_ref * (r_ref.transpose() * j_ref)); + } } } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc index ca36ce07614..19fa17cc37d 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc @@ -39,7 +39,7 @@ namespace ceres { namespace internal { -CXSparse::CXSparse() : scratch_size_(0), scratch_(NULL) { +CXSparse::CXSparse() : scratch_(NULL), scratch_size_(0) { } CXSparse::~CXSparse() { @@ -116,12 +116,12 @@ cs_di* CXSparse::CreateSparseMatrix(TripletSparseMatrix* tsm) { return cs_compress(&tsm_wrapper); } -void CXSparse::Free(cs_di* factor) { - cs_free(factor); +void CXSparse::Free(cs_di* sparse_matrix) { + cs_di_spfree(sparse_matrix); } -void CXSparse::Free(cs_dis* factor) { - cs_sfree(factor); +void CXSparse::Free(cs_dis* symbolic_factorization) { + cs_di_sfree(symbolic_factorization); } } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h index d3b64fcd1a5..dd5eadc8da8 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h +++ b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h @@ -72,9 +72,8 @@ class CXSparse { // The returned matrix should be deallocated with Free when not used anymore. cs_dis* AnalyzeCholesky(cs_di* A); - // Deallocates the memory of a matrix obtained from AnalyzeCholesky. - void Free(cs_di* factor); - void Free(cs_dis* factor); + void Free(cs_di* sparse_matrix); + void Free(cs_dis* symbolic_factorization); private: // Cached scratch space diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_jacobian_writer.h b/extern/libmv/third_party/ceres/internal/ceres/dense_jacobian_writer.h index 1177b83a556..be743a8591c 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/dense_jacobian_writer.h +++ b/extern/libmv/third_party/ceres/internal/ceres/dense_jacobian_writer.h @@ -62,7 +62,8 @@ class DenseJacobianWriter { SparseMatrix* CreateJacobian() const { return new DenseSparseMatrix(program_->NumResiduals(), - program_->NumEffectiveParameters()); + program_->NumEffectiveParameters(), + true); } void Write(int residual_id, @@ -87,10 +88,10 @@ class DenseJacobianWriter { continue; } - int parameter_block_size = parameter_block->LocalSize(); - MatrixRef parameter_jacobian(jacobians[j], - num_residuals, - parameter_block_size); + const int parameter_block_size = parameter_block->LocalSize(); + ConstMatrixRef parameter_jacobian(jacobians[j], + num_residuals, + parameter_block_size); dense_jacobian->mutable_matrix().block( residual_offset, diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc index f6bb99abf63..a340e1664f0 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc @@ -34,10 +34,11 @@ #include "Eigen/Dense" #include "ceres/dense_sparse_matrix.h" -#include "ceres/linear_solver.h" #include "ceres/internal/eigen.h" #include "ceres/internal/scoped_ptr.h" +#include "ceres/linear_solver.h" #include "ceres/types.h" +#include "ceres/wall_time.h" namespace ceres { namespace internal { @@ -51,6 +52,8 @@ LinearSolver::Summary DenseNormalCholeskySolver::SolveImpl( const double* b, const LinearSolver::PerSolveOptions& per_solve_options, double* x) { + EventLogger event_logger("DenseNormalCholeskySolver::Solve"); + const int num_rows = A->num_rows(); const int num_cols = A->num_cols(); @@ -58,6 +61,7 @@ LinearSolver::Summary DenseNormalCholeskySolver::SolveImpl( Matrix lhs(num_cols, num_cols); lhs.setZero(); + event_logger.AddEvent("Setup"); // lhs += A'A // // Using rankUpdate instead of GEMM, exposes the fact that its the @@ -73,12 +77,13 @@ LinearSolver::Summary DenseNormalCholeskySolver::SolveImpl( lhs += D.array().square().matrix().asDiagonal(); } - VectorRef(x, num_cols) = - lhs.selfadjointView().ldlt().solve(rhs); - LinearSolver::Summary summary; summary.num_iterations = 1; summary.termination_type = TOLERANCE; + VectorRef(x, num_cols) = + lhs.selfadjointView().ldlt().solve(rhs); + event_logger.AddEvent("Solve"); + return summary; } diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc index 2b329ee0e9c..1fb9709b42a 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc @@ -34,10 +34,11 @@ #include "Eigen/Dense" #include "ceres/dense_sparse_matrix.h" -#include "ceres/linear_solver.h" #include "ceres/internal/eigen.h" #include "ceres/internal/scoped_ptr.h" +#include "ceres/linear_solver.h" #include "ceres/types.h" +#include "ceres/wall_time.h" namespace ceres { namespace internal { @@ -50,10 +51,10 @@ LinearSolver::Summary DenseQRSolver::SolveImpl( const double* b, const LinearSolver::PerSolveOptions& per_solve_options, double* x) { + EventLogger event_logger("DenseQRSolver::Solve"); + const int num_rows = A->num_rows(); const int num_cols = A->num_cols(); - VLOG(2) << "DenseQRSolver: " - << num_rows << " x " << num_cols << " system."; if (per_solve_options.D != NULL) { // Temporarily append a diagonal block to the A matrix, but undo @@ -62,18 +63,18 @@ LinearSolver::Summary DenseQRSolver::SolveImpl( } // rhs = [b;0] to account for the additional rows in the lhs. - Vector rhs(num_rows + ((per_solve_options.D != NULL) ? num_cols : 0)); - rhs.setZero(); - rhs.head(num_rows) = ConstVectorRef(b, num_rows); + const int augmented_num_rows = + num_rows + ((per_solve_options.D != NULL) ? num_cols : 0); + if (rhs_.rows() != augmented_num_rows) { + rhs_.resize(augmented_num_rows); + rhs_.setZero(); + } + rhs_.head(num_rows) = ConstVectorRef(b, num_rows); + event_logger.AddEvent("Setup"); // Solve the system. - VectorRef(x, num_cols) = A->matrix().colPivHouseholderQr().solve(rhs); - - VLOG(3) << "A:\n" << A->matrix(); - VLOG(3) << "x:\n" << VectorRef(x, num_cols); - VLOG(3) << "b:\n" << rhs; - VLOG(3) << "error: " << (A->matrix() * VectorRef(x, num_cols) - rhs).norm(); - + VectorRef(x, num_cols) = A->matrix().colPivHouseholderQr().solve(rhs_); + event_logger.AddEvent("Solve"); if (per_solve_options.D != NULL) { // Undo the modifications to the matrix A. @@ -86,6 +87,8 @@ LinearSolver::Summary DenseQRSolver::SolveImpl( LinearSolver::Summary summary; summary.num_iterations = 1; summary.termination_type = TOLERANCE; + + event_logger.AddEvent("TearDown"); return summary; } diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h b/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h index dd683a8c4ea..f78fa72c5f3 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h +++ b/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h @@ -33,6 +33,7 @@ #define CERES_INTERNAL_DENSE_QR_SOLVER_H_ #include "ceres/linear_solver.h" +#include "ceres/internal/eigen.h" #include "ceres/internal/macros.h" namespace ceres { @@ -90,6 +91,7 @@ class DenseQRSolver: public DenseSparseMatrixSolver { double* x); const LinearSolver::Options options_; + Vector rhs_; CERES_DISALLOW_COPY_AND_ASSIGN(DenseQRSolver); }; diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc index 86730cc101b..978ac6abe15 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc @@ -47,6 +47,20 @@ DenseSparseMatrix::DenseSparseMatrix(int num_rows, int num_cols) m_.setZero(); } +DenseSparseMatrix::DenseSparseMatrix(int num_rows, + int num_cols, + bool reserve_diagonal) + : has_diagonal_appended_(false), + has_diagonal_reserved_(reserve_diagonal) { + // Allocate enough space for the diagonal. + if (reserve_diagonal) { + m_.resize(num_rows + num_cols, num_cols); + } else { + m_.resize(num_rows, num_cols); + } + m_.setZero(); +} + DenseSparseMatrix::DenseSparseMatrix(const TripletSparseMatrix& m) : m_(Eigen::MatrixXd::Zero(m.num_rows(), m.num_cols())), has_diagonal_appended_(false), @@ -105,7 +119,7 @@ void DenseSparseMatrix::ScaleColumns(const double* scale) { } void DenseSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const { - *dense_matrix = m_; + *dense_matrix = m_.block(0, 0, num_rows(), num_cols()); } #ifndef CERES_NO_PROTOCOL_BUFFERS diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h index e7ad14d0ee6..1e4d499b631 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h +++ b/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h @@ -57,6 +57,7 @@ class DenseSparseMatrix : public SparseMatrix { #endif DenseSparseMatrix(int num_rows, int num_cols); + DenseSparseMatrix(int num_rows, int num_cols, bool reserve_diagonal); virtual ~DenseSparseMatrix() {} diff --git a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc index 668fa54b8b8..a330ad2c7a2 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc @@ -35,7 +35,7 @@ #include "ceres/array_utils.h" #include "ceres/internal/eigen.h" #include "ceres/linear_solver.h" -#include "ceres/polynomial_solver.h" +#include "ceres/polynomial.h" #include "ceres/sparse_matrix.h" #include "ceres/trust_region_strategy.h" #include "ceres/types.h" @@ -87,7 +87,7 @@ TrustRegionStrategy::Summary DoglegStrategy::ComputeStep( // Gauss-Newton and gradient vectors are always available, only a // new interpolant need to be computed. For the subspace case, // the subspace and the two-dimensional model are also still valid. - switch(dogleg_type_) { + switch (dogleg_type_) { case TRADITIONAL_DOGLEG: ComputeTraditionalDoglegStep(step); break; @@ -135,7 +135,7 @@ TrustRegionStrategy::Summary DoglegStrategy::ComputeStep( summary.termination_type = linear_solver_summary.termination_type; if (linear_solver_summary.termination_type != FAILURE) { - switch(dogleg_type_) { + switch (dogleg_type_) { // Interpolate the Cauchy point and the Gauss-Newton step. case TRADITIONAL_DOGLEG: ComputeTraditionalDoglegStep(step); @@ -415,15 +415,15 @@ Vector DoglegStrategy::MakePolynomialForBoundaryConstrainedProblem() const { const double trB = subspace_B_.trace(); const double r2 = radius_ * radius_; Matrix2d B_adj; - B_adj << subspace_B_(1,1) , -subspace_B_(0,1), - -subspace_B_(1,0) , subspace_B_(0,0); + B_adj << subspace_B_(1, 1) , -subspace_B_(0, 1), + -subspace_B_(1, 0) , subspace_B_(0, 0); Vector polynomial(5); polynomial(0) = r2; polynomial(1) = 2.0 * r2 * trB; - polynomial(2) = r2 * ( trB * trB + 2.0 * detB ) - subspace_g_.squaredNorm(); - polynomial(3) = -2.0 * ( subspace_g_.transpose() * B_adj * subspace_g_ - - r2 * detB * trB ); + polynomial(2) = r2 * (trB * trB + 2.0 * detB) - subspace_g_.squaredNorm(); + polynomial(3) = -2.0 * (subspace_g_.transpose() * B_adj * subspace_g_ + - r2 * detB * trB); polynomial(4) = r2 * detB * detB - (B_adj * subspace_g_).squaredNorm(); return polynomial; @@ -598,7 +598,7 @@ void DoglegStrategy::StepAccepted(double step_quality) { // Reduce the regularization multiplier, in the hope that whatever // was causing the rank deficiency has gone away and we can return // to doing a pure Gauss-Newton solve. - mu_ = max(min_mu_, 2.0 * mu_ / mu_increase_factor_ ); + mu_ = max(min_mu_, 2.0 * mu_ / mu_increase_factor_); reuse_ = false; } diff --git a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h index bff1689aa4a..7131467d6ce 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h +++ b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h @@ -53,8 +53,8 @@ namespace internal { // This finds the exact optimum over the two-dimensional subspace // spanned by the two Dogleg vectors. class DoglegStrategy : public TrustRegionStrategy { -public: - DoglegStrategy(const TrustRegionStrategy::Options& options); + public: + explicit DoglegStrategy(const TrustRegionStrategy::Options& options); virtual ~DoglegStrategy() {} // TrustRegionStrategy interface diff --git a/extern/libmv/third_party/ceres/internal/ceres/evaluator.h b/extern/libmv/third_party/ceres/internal/ceres/evaluator.h index 6aa30d7b739..14a88188145 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/evaluator.h +++ b/extern/libmv/third_party/ceres/internal/ceres/evaluator.h @@ -32,14 +32,17 @@ #ifndef CERES_INTERNAL_EVALUATOR_H_ #define CERES_INTERNAL_EVALUATOR_H_ +#include #include #include + +#include "ceres/execution_summary.h" #include "ceres/internal/port.h" #include "ceres/types.h" namespace ceres { -class CRSMatrix; +struct CRSMatrix; namespace internal { @@ -152,6 +155,18 @@ class Evaluator { // The number of residuals in the optimization problem. virtual int NumResiduals() const = 0; + + // The following two methods return copies instead of references so + // that the base class implementation does not have to worry about + // life time issues. Further, these calls are not expected to be + // frequent or performance sensitive. + virtual map CallStatistics() const { + return map(); + } + + virtual map TimeStatistics() const { + return map(); + } }; } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/execution_summary.h b/extern/libmv/third_party/ceres/internal/ceres/execution_summary.h new file mode 100644 index 00000000000..29bdc69ecd7 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/execution_summary.h @@ -0,0 +1,90 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2013 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#ifndef CERES_INTERNAL_EXECUTION_SUMMARY_H_ +#define CERES_INTERNAL_EXECUTION_SUMMARY_H_ + +#include +#include + +#include "ceres/internal/port.h" +#include "ceres/wall_time.h" +#include "ceres/mutex.h" + +namespace ceres { +namespace internal { + +// Struct used by various objects to report statistics and other +// information about their execution. e.g., ExecutionSummary::times +// can be used for reporting times associated with various activities. +class ExecutionSummary { + public: + void IncrementTimeBy(const string& name, const double value) { + CeresMutexLock l(×_mutex_); + times_[name] += value; + } + + void IncrementCall(const string& name) { + CeresMutexLock l(&calls_mutex_); + calls_[name] += 1; + } + + const map& times() const { return times_; } + const map& calls() const { return calls_; } + + private: + Mutex times_mutex_; + map times_; + + Mutex calls_mutex_; + map calls_; +}; + +class ScopedExecutionTimer { + public: + ScopedExecutionTimer(const string& name, ExecutionSummary* summary) + : start_time_(WallTimeInSeconds()), + name_(name), + summary_(summary) {} + + ~ScopedExecutionTimer() { + summary_->IncrementTimeBy(name_, WallTimeInSeconds() - start_time_); + } + + private: + const double start_time_; + const string name_; + ExecutionSummary* summary_; +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_EXECUTION_SUMMARY_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/file.cc b/extern/libmv/third_party/ceres/internal/ceres/file.cc index 6fe7557246d..5226c85e6ee 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/file.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/file.cc @@ -30,8 +30,9 @@ // // Really simple file IO. +#include "ceres/file.h" + #include -#include "file.h" #include "glog/logging.h" namespace ceres { diff --git a/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc b/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc index 7fb3ed7b3a8..3edf95da6e0 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc @@ -154,8 +154,8 @@ class GradientCheckingCostFunction : public CostFunction { "Jacobian for " "block %d: (%ld by %ld)) " "==========\n", k, - term_jacobians[k].rows(), - term_jacobians[k].cols()); + static_cast(term_jacobians[k].rows()), + static_cast(term_jacobians[k].cols())); // The funny spacing creates appropriately aligned column headers. m += " block row col user dx/dy num diff dx/dy " "abs error relative error parameter residual\n"; diff --git a/extern/libmv/third_party/ceres/internal/ceres/graph.h b/extern/libmv/third_party/ceres/internal/ceres/graph.h index 2c0f6d28e54..5f92d4d4df2 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/graph.h +++ b/extern/libmv/third_party/ceres/internal/ceres/graph.h @@ -32,12 +32,13 @@ #define CERES_INTERNAL_GRAPH_H_ #include -#include +#include #include "ceres/integral_types.h" #include "ceres/map_util.h" #include "ceres/collections_port.h" #include "ceres/internal/macros.h" #include "ceres/types.h" +#include "glog/logging.h" namespace ceres { namespace internal { @@ -65,6 +66,28 @@ class Graph { AddVertex(vertex, 1.0); } + bool RemoveVertex(const Vertex& vertex) { + if (vertices_.find(vertex) == vertices_.end()) { + return false; + } + + vertices_.erase(vertex); + vertex_weights_.erase(vertex); + const HashSet& sinks = edges_[vertex]; + for (typename HashSet::const_iterator it = sinks.begin(); + it != sinks.end(); ++it) { + if (vertex < *it) { + edge_weights_.erase(make_pair(vertex, *it)); + } else { + edge_weights_.erase(make_pair(*it, vertex)); + } + edges_[*it].erase(vertex); + } + + edges_.erase(vertex); + return true; + } + // Add a weighted edge between the vertex1 and vertex2. Calling // AddEdge on a pair of vertices which do not exist in the graph yet // will result in undefined behavior. diff --git a/extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h b/extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h index 3b42d936336..2e6eec0e6d8 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h +++ b/extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h @@ -33,10 +33,12 @@ #ifndef CERES_INTERNAL_GRAPH_ALGORITHMS_H_ #define CERES_INTERNAL_GRAPH_ALGORITHMS_H_ +#include #include -#include +#include #include "ceres/collections_port.h" #include "ceres/graph.h" +#include "glog/logging.h" namespace ceres { namespace internal { diff --git a/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc index 679c41f2431..cf5562ac771 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc @@ -33,6 +33,7 @@ #include #include #include + #include "Eigen/Dense" #include "ceres/block_sparse_matrix.h" #include "ceres/block_structure.h" @@ -41,9 +42,12 @@ #include "ceres/internal/eigen.h" #include "ceres/internal/scoped_ptr.h" #include "ceres/linear_solver.h" +#include "ceres/preconditioner.h" +#include "ceres/schur_jacobi_preconditioner.h" #include "ceres/triplet_sparse_matrix.h" #include "ceres/types.h" #include "ceres/visibility_based_preconditioner.h" +#include "ceres/wall_time.h" #include "glog/logging.h" namespace ceres { @@ -62,12 +66,14 @@ LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl( const double* b, const LinearSolver::PerSolveOptions& per_solve_options, double* x) { + EventLogger event_logger("IterativeSchurComplementSolver::Solve"); + CHECK_NOTNULL(A->block_structure()); // Initialize a ImplicitSchurComplement object. if (schur_complement_ == NULL) { schur_complement_.reset( - new ImplicitSchurComplement(options_.num_eliminate_blocks, + new ImplicitSchurComplement(options_.elimination_groups[0], options_.preconditioner_type == JACOBI)); } schur_complement_->Init(*A, per_solve_options.D, b); @@ -89,44 +95,58 @@ LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl( cg_per_solve_options.r_tolerance = per_solve_options.r_tolerance; cg_per_solve_options.q_tolerance = per_solve_options.q_tolerance; - bool is_preconditioner_good = false; + Preconditioner::Options preconditioner_options; + preconditioner_options.type = options_.preconditioner_type; + preconditioner_options.sparse_linear_algebra_library = + options_.sparse_linear_algebra_library; + preconditioner_options.use_block_amd = options_.use_block_amd; + preconditioner_options.num_threads = options_.num_threads; + preconditioner_options.row_block_size = options_.row_block_size; + preconditioner_options.e_block_size = options_.e_block_size; + preconditioner_options.f_block_size = options_.f_block_size; + preconditioner_options.elimination_groups = options_.elimination_groups; + switch (options_.preconditioner_type) { case IDENTITY: - is_preconditioner_good = true; break; case JACOBI: - // We need to strip the constness of the block_diagonal_FtF_inverse - // matrix here because the only other way to initialize the struct - // cg_solve_options would be to add a constructor to it. We know - // that the only method ever called on the preconditioner is the - // RightMultiply which is a const method so we don't need to worry - // about the object getting modified. - cg_per_solve_options.preconditioner = - const_cast( - schur_complement_->block_diagonal_FtF_inverse()); - is_preconditioner_good = true; + preconditioner_.reset( + new SparseMatrixPreconditionerWrapper( + schur_complement_->block_diagonal_FtF_inverse())); break; case SCHUR_JACOBI: + if (preconditioner_.get() == NULL) { + preconditioner_.reset( + new SchurJacobiPreconditioner( + *A->block_structure(), preconditioner_options)); + } + break; case CLUSTER_JACOBI: case CLUSTER_TRIDIAGONAL: - if (visibility_based_preconditioner_.get() == NULL) { - visibility_based_preconditioner_.reset( - new VisibilityBasedPreconditioner(*A->block_structure(), options_)); + if (preconditioner_.get() == NULL) { + preconditioner_.reset( + new VisibilityBasedPreconditioner( + *A->block_structure(), preconditioner_options)); } - is_preconditioner_good = - visibility_based_preconditioner_->Update(*A, per_solve_options.D); - cg_per_solve_options.preconditioner = - visibility_based_preconditioner_.get(); break; default: LOG(FATAL) << "Unknown Preconditioner Type"; } + bool preconditioner_update_was_successful = true; + if (preconditioner_.get() != NULL) { + preconditioner_update_was_successful = + preconditioner_->Update(*A, per_solve_options.D); + cg_per_solve_options.preconditioner = preconditioner_.get(); + } + + event_logger.AddEvent("Setup"); + LinearSolver::Summary cg_summary; cg_summary.num_iterations = 0; cg_summary.termination_type = FAILURE; - if (is_preconditioner_good) { + if (preconditioner_update_was_successful) { cg_summary = cg_solver.Solve(schur_complement_.get(), schur_complement_->rhs().data(), cg_per_solve_options, @@ -138,6 +158,8 @@ LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl( } VLOG(2) << "CG Iterations : " << cg_summary.num_iterations; + + event_logger.AddEvent("Solve"); return cg_summary; } diff --git a/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h b/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h index cfeb65e1eec..f8abe04c142 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h +++ b/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h @@ -39,13 +39,12 @@ namespace ceres { namespace internal { -class BlockSparseMatrix; class BlockSparseMatrixBase; class ImplicitSchurComplement; -class VisibilityBasedPreconditioner; +class Preconditioner; // This class implements an iterative solver for the linear least -// squares problems that have a bi-partitte sparsity structure common +// squares problems that have a bi-partite sparsity structure common // to Structure from Motion problems. // // The algorithm used by this solver was developed in a series of @@ -70,9 +69,7 @@ class VisibilityBasedPreconditioner; // "Iterative Methods for Sparse Linear Systems". class IterativeSchurComplementSolver : public BlockSparseMatrixBaseSolver { public: - explicit IterativeSchurComplementSolver( - const LinearSolver::Options& options); - + explicit IterativeSchurComplementSolver(const LinearSolver::Options& options); virtual ~IterativeSchurComplementSolver(); private: @@ -84,8 +81,9 @@ class IterativeSchurComplementSolver : public BlockSparseMatrixBaseSolver { LinearSolver::Options options_; scoped_ptr schur_complement_; - scoped_ptr visibility_based_preconditioner_; + scoped_ptr preconditioner_; Vector reduced_linear_system_solution_; + CERES_DISALLOW_COPY_AND_ASSIGN(IterativeSchurComplementSolver); }; } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h b/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h index 90c21789797..344e3285422 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h +++ b/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h @@ -43,8 +43,9 @@ namespace internal { // // http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf class LevenbergMarquardtStrategy : public TrustRegionStrategy { -public: - LevenbergMarquardtStrategy(const TrustRegionStrategy::Options& options); + public: + explicit LevenbergMarquardtStrategy( + const TrustRegionStrategy::Options& options); virtual ~LevenbergMarquardtStrategy(); // TrustRegionStrategy interface diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search.cc b/extern/libmv/third_party/ceres/internal/ceres/line_search.cc new file mode 100644 index 00000000000..e7508caec56 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/line_search.cc @@ -0,0 +1,211 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#include "ceres/line_search.h" + +#include +#include "ceres/fpclassify.h" +#include "ceres/evaluator.h" +#include "ceres/internal/eigen.h" +#include "ceres/polynomial.h" + + +namespace ceres { +namespace internal { +namespace { + +FunctionSample ValueSample(const double x, const double value) { + FunctionSample sample; + sample.x = x; + sample.value = value; + sample.value_is_valid = true; + return sample; +}; + +FunctionSample ValueAndGradientSample(const double x, + const double value, + const double gradient) { + FunctionSample sample; + sample.x = x; + sample.value = value; + sample.gradient = gradient; + sample.value_is_valid = true; + sample.gradient_is_valid = true; + return sample; +}; + +} // namespace + +LineSearchFunction::LineSearchFunction(Evaluator* evaluator) + : evaluator_(evaluator), + position_(evaluator->NumParameters()), + direction_(evaluator->NumEffectiveParameters()), + evaluation_point_(evaluator->NumParameters()), + scaled_direction_(evaluator->NumEffectiveParameters()), + gradient_(evaluator->NumEffectiveParameters()) { +} + +void LineSearchFunction::Init(const Vector& position, + const Vector& direction) { + position_ = position; + direction_ = direction; +} + +bool LineSearchFunction::Evaluate(const double x, double* f, double* g) { + scaled_direction_ = x * direction_; + if (!evaluator_->Plus(position_.data(), + scaled_direction_.data(), + evaluation_point_.data())) { + return false; + } + + if (g == NULL) { + return (evaluator_->Evaluate(evaluation_point_.data(), + f, NULL, NULL, NULL) && + IsFinite(*f)); + } + + if (!evaluator_->Evaluate(evaluation_point_.data(), + f, + NULL, + gradient_.data(), NULL)) { + return false; + } + + *g = direction_.dot(gradient_); + return IsFinite(*f) && IsFinite(*g); +} + +void ArmijoLineSearch::Search(const LineSearch::Options& options, + const double initial_step_size, + const double initial_cost, + const double initial_gradient, + Summary* summary) { + *CHECK_NOTNULL(summary) = LineSearch::Summary(); + Function* function = options.function; + + double previous_step_size = 0.0; + double previous_cost = 0.0; + double previous_gradient = 0.0; + bool previous_step_size_is_valid = false; + + double step_size = initial_step_size; + double cost = 0.0; + double gradient = 0.0; + bool step_size_is_valid = false; + + ++summary->num_evaluations; + step_size_is_valid = + function->Evaluate(step_size, + &cost, + options.interpolation_degree < 2 ? NULL : &gradient); + while (!step_size_is_valid || cost > (initial_cost + + options.sufficient_decrease + * initial_gradient + * step_size)) { + // If step_size_is_valid is not true we treat it as if the cost at + // that point is not large enough to satisfy the sufficient + // decrease condition. + + const double current_step_size = step_size; + // Backtracking search. Each iteration of this loop finds a new point + + if ((options.interpolation_degree == 0) || !step_size_is_valid) { + // Backtrack by halving the step_size; + step_size *= 0.5; + } else { + // Backtrack by interpolating the function and gradient values + // and minimizing the corresponding polynomial. + + vector samples; + samples.push_back(ValueAndGradientSample(0.0, + initial_cost, + initial_gradient)); + + if (options.interpolation_degree == 1) { + // Two point interpolation using function values and the + // initial gradient. + samples.push_back(ValueSample(step_size, cost)); + + if (options.use_higher_degree_interpolation_when_possible && + summary->num_evaluations > 1 && + previous_step_size_is_valid) { + // Three point interpolation, using function values and the + // initial gradient. + samples.push_back(ValueSample(previous_step_size, previous_cost)); + } + } else { + // Two point interpolation using the function values and the gradients. + samples.push_back(ValueAndGradientSample(step_size, + cost, + gradient)); + + if (options.use_higher_degree_interpolation_when_possible && + summary->num_evaluations > 1 && + previous_step_size_is_valid) { + // Three point interpolation using the function values and + // the gradients. + samples.push_back(ValueAndGradientSample(previous_step_size, + previous_cost, + previous_gradient)); + } + } + + double min_value; + MinimizeInterpolatingPolynomial(samples, 0.0, current_step_size, + &step_size, &min_value); + step_size = + min(max(step_size, + options.min_relative_step_size_change * current_step_size), + options.max_relative_step_size_change * current_step_size); + } + + previous_step_size = current_step_size; + previous_cost = cost; + previous_gradient = gradient; + + if (fabs(initial_gradient) * step_size < options.step_size_threshold) { + LOG(WARNING) << "Line search failed: step_size too small: " << step_size; + return; + } + + ++summary->num_evaluations; + step_size_is_valid = + function->Evaluate(step_size, + &cost, + options.interpolation_degree < 2 ? NULL : &gradient); + } + + summary->optimal_step_size = step_size; + summary->success = true; +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search.h b/extern/libmv/third_party/ceres/internal/ceres/line_search.h new file mode 100644 index 00000000000..fccf63b598a --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/line_search.h @@ -0,0 +1,212 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) +// +// Interface for and implementation of various Line search algorithms. + +#ifndef CERES_INTERNAL_LINE_SEARCH_H_ +#define CERES_INTERNAL_LINE_SEARCH_H_ + +#include +#include +#include "ceres/internal/eigen.h" +#include "ceres/internal/port.h" + +namespace ceres { +namespace internal { + +class Evaluator; + +// Line search is another name for a one dimensional optimization +// algorithm. The name "line search" comes from the fact one +// dimensional optimization problems that arise as subproblems of +// general multidimensional optimization problems. +// +// While finding the exact minimum of a one dimensionl function is +// hard, instances of LineSearch find a point that satisfies a +// sufficient decrease condition. Depending on the particular +// condition used, we get a variety of different line search +// algorithms, e.g., Armijo, Wolfe etc. +class LineSearch { + public: + class Function; + + struct Options { + Options() + : interpolation_degree(1), + use_higher_degree_interpolation_when_possible(false), + sufficient_decrease(1e-4), + min_relative_step_size_change(1e-3), + max_relative_step_size_change(0.6), + step_size_threshold(1e-9), + function(NULL) {} + + // TODO(sameeragarwal): Replace this with enums which are common + // across various line searches. + // + // Degree of the polynomial used to approximate the objective + // function. Valid values are {0, 1, 2}. + // + // For Armijo line search + // + // 0: Bisection based backtracking search. + // 1: Quadratic interpolation. + // 2: Cubic interpolation. + int interpolation_degree; + + // Usually its possible to increase the degree of the + // interpolation polynomial by storing and using an extra point. + bool use_higher_degree_interpolation_when_possible; + + // Armijo line search parameters. + + // Solving the line search problem exactly is computationally + // prohibitive. Fortunately, line search based optimization + // algorithms can still guarantee convergence if instead of an + // exact solution, the line search algorithm returns a solution + // which decreases the value of the objective function + // sufficiently. More precisely, we are looking for a step_size + // s.t. + // + // f(step_size) <= f(0) + sufficient_decrease * f'(0) * step_size + double sufficient_decrease; + + // In each iteration of the Armijo line search, + // + // new_step_size >= min_relative_step_size_change * step_size + double min_relative_step_size_change; + + // In each iteration of the Armijo line search, + // + // new_step_size <= max_relative_step_size_change * step_size + double max_relative_step_size_change; + + // If during the line search, the step_size falls below this + // value, it is truncated to zero. + double step_size_threshold; + + // The one dimensional function that the line search algorithm + // minimizes. + Function* function; + }; + + // An object used by the line search to access the function values + // and gradient of the one dimensional function being optimized. + // + // In practice, this object will provide access to the objective + // function value and the directional derivative of the underlying + // optimization problem along a specific search direction. + // + // See LineSearchFunction for an example implementation. + class Function { + public: + virtual ~Function() {} + // Evaluate the line search objective + // + // f(x) = p(position + x * direction) + // + // Where, p is the objective function of the general optimization + // problem. + // + // g is the gradient f'(x) at x. + // + // f must not be null. The gradient is computed only if g is not null. + virtual bool Evaluate(double x, double* f, double* g) = 0; + }; + + // Result of the line search. + struct Summary { + Summary() + : success(false), + optimal_step_size(0.0), + num_evaluations(0) {} + + bool success; + double optimal_step_size; + int num_evaluations; + }; + + virtual ~LineSearch() {} + + // Perform the line search. + // + // initial_step_size must be a positive number. + // + // initial_cost and initial_gradient are the values and gradient of + // the function at zero. + // summary must not be null and will contain the result of the line + // search. + // + // Summary::success is true if a non-zero step size is found. + virtual void Search(const LineSearch::Options& options, + double initial_step_size, + double initial_cost, + double initial_gradient, + Summary* summary) = 0; +}; + +class LineSearchFunction : public LineSearch::Function { + public: + explicit LineSearchFunction(Evaluator* evaluator); + virtual ~LineSearchFunction() {} + void Init(const Vector& position, const Vector& direction); + virtual bool Evaluate(const double x, double* f, double* g); + + private: + Evaluator* evaluator_; + Vector position_; + Vector direction_; + + // evaluation_point = Evaluator::Plus(position_, x * direction_); + Vector evaluation_point_; + + // scaled_direction = x * direction_; + Vector scaled_direction_; + Vector gradient_; +}; + +// Backtracking and interpolation based Armijo line search. This +// implementation is based on the Armijo line search that ships in the +// minFunc package by Mark Schmidt. +// +// For more details: http://www.di.ens.fr/~mschmidt/Software/minFunc.html +class ArmijoLineSearch : public LineSearch { + public: + virtual ~ArmijoLineSearch() {} + virtual void Search(const LineSearch::Options& options, + double initial_step_size, + double initial_cost, + double initial_gradient, + Summary* summary); +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_LINE_SEARCH_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.cc b/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.cc new file mode 100644 index 00000000000..2f27a78301a --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.cc @@ -0,0 +1,145 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#include "ceres/line_search_direction.h" +#include "ceres/line_search_minimizer.h" +#include "ceres/low_rank_inverse_hessian.h" +#include "ceres/internal/eigen.h" +#include "glog/logging.h" + +namespace ceres { +namespace internal { + +class SteepestDescent : public LineSearchDirection { + public: + virtual ~SteepestDescent() {} + bool NextDirection(const LineSearchMinimizer::State& previous, + const LineSearchMinimizer::State& current, + Vector* search_direction) { + *search_direction = -current.gradient; + return true; + } +}; + +class NonlinearConjugateGradient : public LineSearchDirection { + public: + NonlinearConjugateGradient(const NonlinearConjugateGradientType type, + const double function_tolerance) + : type_(type), + function_tolerance_(function_tolerance) { + } + + bool NextDirection(const LineSearchMinimizer::State& previous, + const LineSearchMinimizer::State& current, + Vector* search_direction) { + double beta = 0.0; + Vector gradient_change; + switch (type_) { + case FLETCHER_REEVES: + beta = current.gradient_squared_norm / previous.gradient_squared_norm; + break; + case POLAK_RIBIRERE: + gradient_change = current.gradient - previous.gradient; + beta = (current.gradient.dot(gradient_change) / + previous.gradient_squared_norm); + break; + case HESTENES_STIEFEL: + gradient_change = current.gradient - previous.gradient; + beta = (current.gradient.dot(gradient_change) / + previous.search_direction.dot(gradient_change)); + break; + default: + LOG(FATAL) << "Unknown nonlinear conjugate gradient type: " << type_; + } + + *search_direction = -current.gradient + beta * previous.search_direction; + const double directional_derivative = + current. gradient.dot(*search_direction); + if (directional_derivative > -function_tolerance_) { + LOG(WARNING) << "Restarting non-linear conjugate gradients: " + << directional_derivative; + *search_direction = -current.gradient; + }; + + return true; + } + + private: + const NonlinearConjugateGradientType type_; + const double function_tolerance_; +}; + +class LBFGS : public LineSearchDirection { + public: + LBFGS(const int num_parameters, const int max_lbfgs_rank) + : low_rank_inverse_hessian_(num_parameters, max_lbfgs_rank) {} + + virtual ~LBFGS() {} + + bool NextDirection(const LineSearchMinimizer::State& previous, + const LineSearchMinimizer::State& current, + Vector* search_direction) { + low_rank_inverse_hessian_.Update( + previous.search_direction * previous.step_size, + current.gradient - previous.gradient); + search_direction->setZero(); + low_rank_inverse_hessian_.RightMultiply(current.gradient.data(), + search_direction->data()); + *search_direction *= -1.0; + return true; + } + + private: + LowRankInverseHessian low_rank_inverse_hessian_; +}; + +LineSearchDirection* +LineSearchDirection::Create(const LineSearchDirection::Options& options) { + if (options.type == STEEPEST_DESCENT) { + return new SteepestDescent; + } + + if (options.type == NONLINEAR_CONJUGATE_GRADIENT) { + return new NonlinearConjugateGradient( + options.nonlinear_conjugate_gradient_type, + options.function_tolerance); + } + + if (options.type == ceres::LBFGS) { + return new ceres::internal::LBFGS(options.num_parameters, + options.max_lbfgs_rank); + } + + LOG(ERROR) << "Unknown line search direction type: " << options.type; + return NULL; +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.h b/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.h new file mode 100644 index 00000000000..71063ab8414 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.h @@ -0,0 +1,70 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#ifndef CERES_INTERNAL_LINE_SEARCH_DIRECTION_H_ +#define CERES_INTERNAL_LINE_SEARCH_DIRECTION_H_ + +#include "ceres/internal/eigen.h" +#include "ceres/line_search_minimizer.h" +#include "ceres/types.h" + +namespace ceres { +namespace internal { + +class LineSearchDirection { + public: + struct Options { + Options() + : num_parameters(0), + type(LBFGS), + nonlinear_conjugate_gradient_type(FLETCHER_REEVES), + function_tolerance(1e-12), + max_lbfgs_rank(20) { + } + + int num_parameters; + LineSearchDirectionType type; + NonlinearConjugateGradientType nonlinear_conjugate_gradient_type; + double function_tolerance; + int max_lbfgs_rank; + }; + + static LineSearchDirection* Create(const Options& options); + + virtual ~LineSearchDirection() {} + virtual bool NextDirection(const LineSearchMinimizer::State& previous, + const LineSearchMinimizer::State& current, + Vector* search_direction) = 0; +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_LINE_SEARCH_DIRECTION_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.cc b/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.cc new file mode 100644 index 00000000000..ca7d639c5ef --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.cc @@ -0,0 +1,283 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) +// +// Generic loop for line search based optimization algorithms. +// +// This is primarily inpsired by the minFunc packaged written by Mark +// Schmidt. +// +// http://www.di.ens.fr/~mschmidt/Software/minFunc.html +// +// For details on the theory and implementation see "Numerical +// Optimization" by Nocedal & Wright. + +#include "ceres/line_search_minimizer.h" + +#include +#include +#include +#include +#include + +#include "Eigen/Dense" +#include "ceres/array_utils.h" +#include "ceres/evaluator.h" +#include "ceres/internal/eigen.h" +#include "ceres/internal/port.h" +#include "ceres/internal/scoped_ptr.h" +#include "ceres/line_search.h" +#include "ceres/line_search_direction.h" +#include "ceres/stringprintf.h" +#include "ceres/types.h" +#include "ceres/wall_time.h" +#include "glog/logging.h" + +namespace ceres { +namespace internal { +namespace { +// Small constant for various floating point issues. +// TODO(sameeragarwal): Change to a better name if this has only one +// use. +const double kEpsilon = 1e-12; + +bool Evaluate(Evaluator* evaluator, + const Vector& x, + LineSearchMinimizer::State* state) { + const bool status = evaluator->Evaluate(x.data(), + &(state->cost), + NULL, + state->gradient.data(), + NULL); + if (status) { + state->gradient_squared_norm = state->gradient.squaredNorm(); + state->gradient_max_norm = state->gradient.lpNorm(); + } + + return status; +} + +} // namespace + +void LineSearchMinimizer::Minimize(const Minimizer::Options& options, + double* parameters, + Solver::Summary* summary) { + double start_time = WallTimeInSeconds(); + double iteration_start_time = start_time; + + Evaluator* evaluator = CHECK_NOTNULL(options.evaluator); + const int num_parameters = evaluator->NumParameters(); + const int num_effective_parameters = evaluator->NumEffectiveParameters(); + + summary->termination_type = NO_CONVERGENCE; + summary->num_successful_steps = 0; + summary->num_unsuccessful_steps = 0; + + VectorRef x(parameters, num_parameters); + + State current_state(num_parameters, num_effective_parameters); + State previous_state(num_parameters, num_effective_parameters); + + Vector delta(num_effective_parameters); + Vector x_plus_delta(num_parameters); + + IterationSummary iteration_summary; + iteration_summary.iteration = 0; + iteration_summary.step_is_valid = false; + iteration_summary.step_is_successful = false; + iteration_summary.cost_change = 0.0; + iteration_summary.gradient_max_norm = 0.0; + iteration_summary.step_norm = 0.0; + iteration_summary.linear_solver_iterations = 0; + iteration_summary.step_solver_time_in_seconds = 0; + + // Do initial cost and Jacobian evaluation. + if (!Evaluate(evaluator, x, ¤t_state)) { + LOG(WARNING) << "Terminating: Cost and gradient evaluation failed."; + summary->termination_type = NUMERICAL_FAILURE; + return; + } + + summary->initial_cost = current_state.cost + summary->fixed_cost; + iteration_summary.cost = current_state.cost + summary->fixed_cost; + + iteration_summary.gradient_max_norm = current_state.gradient_max_norm; + + // The initial gradient max_norm is bounded from below so that we do + // not divide by zero. + const double initial_gradient_max_norm = + max(iteration_summary.gradient_max_norm, kEpsilon); + const double absolute_gradient_tolerance = + options.gradient_tolerance * initial_gradient_max_norm; + + if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) { + summary->termination_type = GRADIENT_TOLERANCE; + VLOG(1) << "Terminating: Gradient tolerance reached." + << "Relative gradient max norm: " + << iteration_summary.gradient_max_norm / initial_gradient_max_norm + << " <= " << options.gradient_tolerance; + return; + } + + iteration_summary.iteration_time_in_seconds = + WallTimeInSeconds() - iteration_start_time; + iteration_summary.cumulative_time_in_seconds = + WallTimeInSeconds() - start_time + + summary->preprocessor_time_in_seconds; + summary->iterations.push_back(iteration_summary); + + LineSearchDirection::Options line_search_direction_options; + line_search_direction_options.num_parameters = num_effective_parameters; + line_search_direction_options.type = options.line_search_direction_type; + line_search_direction_options.nonlinear_conjugate_gradient_type = + options.nonlinear_conjugate_gradient_type; + line_search_direction_options.max_lbfgs_rank = options.max_lbfgs_rank; + scoped_ptr line_search_direction( + LineSearchDirection::Create(line_search_direction_options)); + + LineSearchFunction line_search_function(evaluator); + LineSearch::Options line_search_options; + line_search_options.function = &line_search_function; + + // TODO(sameeragarwal): Make this parameterizable over different + // line searches. + ArmijoLineSearch line_search; + LineSearch::Summary line_search_summary; + + while (true) { + if (!RunCallbacks(options.callbacks, iteration_summary, summary)) { + return; + } + + iteration_start_time = WallTimeInSeconds(); + if (iteration_summary.iteration >= options.max_num_iterations) { + summary->termination_type = NO_CONVERGENCE; + VLOG(1) << "Terminating: Maximum number of iterations reached."; + break; + } + + const double total_solver_time = iteration_start_time - start_time + + summary->preprocessor_time_in_seconds; + if (total_solver_time >= options.max_solver_time_in_seconds) { + summary->termination_type = NO_CONVERGENCE; + VLOG(1) << "Terminating: Maximum solver time reached."; + break; + } + + iteration_summary = IterationSummary(); + iteration_summary.iteration = summary->iterations.back().iteration + 1; + + bool line_search_status = true; + if (iteration_summary.iteration == 1) { + current_state.search_direction = -current_state.gradient; + } else { + line_search_status = line_search_direction->NextDirection( + previous_state, + current_state, + ¤t_state.search_direction); + } + + if (!line_search_status) { + LOG(WARNING) << "Line search direction computation failed. " + "Resorting to steepest descent."; + current_state.search_direction = -current_state.gradient; + } + + line_search_function.Init(x, current_state.search_direction); + current_state.directional_derivative = + current_state.gradient.dot(current_state.search_direction); + + // TODO(sameeragarwal): Refactor this into its own object and add + // explanations for the various choices. + const double initial_step_size = (iteration_summary.iteration == 1) + ? min(1.0, 1.0 / current_state.gradient_max_norm) + : min(1.0, 2.0 * (current_state.cost - previous_state.cost) / + current_state.directional_derivative); + + line_search.Search(line_search_options, + initial_step_size, + current_state.cost, + current_state.directional_derivative, + &line_search_summary); + + current_state.step_size = line_search_summary.optimal_step_size; + delta = current_state.step_size * current_state.search_direction; + + previous_state = current_state; + + // TODO(sameeragarwal): Collect stats. + if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data()) || + !Evaluate(evaluator, x_plus_delta, ¤t_state)) { + LOG(WARNING) << "Evaluation failed."; + } else { + x = x_plus_delta; + } + + iteration_summary.gradient_max_norm = current_state.gradient_max_norm; + if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) { + summary->termination_type = GRADIENT_TOLERANCE; + VLOG(1) << "Terminating: Gradient tolerance reached." + << "Relative gradient max norm: " + << iteration_summary.gradient_max_norm / initial_gradient_max_norm + << " <= " << options.gradient_tolerance; + break; + } + + iteration_summary.cost_change = previous_state.cost - current_state.cost; + const double absolute_function_tolerance = + options.function_tolerance * previous_state.cost; + if (fabs(iteration_summary.cost_change) < absolute_function_tolerance) { + VLOG(1) << "Terminating. Function tolerance reached. " + << "|cost_change|/cost: " + << fabs(iteration_summary.cost_change) / previous_state.cost + << " <= " << options.function_tolerance; + summary->termination_type = FUNCTION_TOLERANCE; + return; + } + + iteration_summary.cost = current_state.cost + summary->fixed_cost; + iteration_summary.step_norm = delta.norm(); + iteration_summary.step_is_valid = true; + iteration_summary.step_is_successful = true; + iteration_summary.step_norm = delta.norm(); + iteration_summary.step_size = current_state.step_size; + iteration_summary.line_search_function_evaluations = + line_search_summary.num_evaluations; + iteration_summary.iteration_time_in_seconds = + WallTimeInSeconds() - iteration_start_time; + iteration_summary.cumulative_time_in_seconds = + WallTimeInSeconds() - start_time + + summary->preprocessor_time_in_seconds; + + summary->iterations.push_back(iteration_summary); + } +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.h b/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.h new file mode 100644 index 00000000000..f82f13984a8 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.h @@ -0,0 +1,77 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#ifndef CERES_INTERNAL_LINE_SEARCH_MINIMIZER_H_ +#define CERES_INTERNAL_LINE_SEARCH_MINIMIZER_H_ + +#include "ceres/minimizer.h" +#include "ceres/solver.h" +#include "ceres/types.h" +#include "ceres/internal/eigen.h" +#include "glog/logging.h" + +namespace ceres { +namespace internal { + +// Generic line search minimization algorithm. +// +// For example usage, see SolverImpl::Minimize. +class LineSearchMinimizer : public Minimizer { + public: + struct State { + State(int num_parameters, + int num_effective_parameters) + : cost(0.0), + gradient(num_effective_parameters), + gradient_squared_norm(0.0), + search_direction(num_effective_parameters), + directional_derivative(0.0), + step_size(0.0) { + } + + double cost; + Vector gradient; + double gradient_squared_norm; + double gradient_max_norm; + Vector search_direction; + double directional_derivative; + double step_size; + }; + + ~LineSearchMinimizer() {} + virtual void Minimize(const Minimizer::Options& options, + double* parameters, + Solver::Summary* summary); +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_LINE_SEARCH_MINIMIZER_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc b/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc index a91e254a663..6c886a1be38 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc @@ -573,13 +573,14 @@ LinearLeastSquaresProblem* LinearLeastSquaresProblem3() { return problem; } -static bool DumpLinearLeastSquaresProblemToConsole(const string& directory, - int iteration, - const SparseMatrix* A, - const double* D, - const double* b, - const double* x, - int num_eliminate_blocks) { +namespace { +bool DumpLinearLeastSquaresProblemToConsole(const string& directory, + int iteration, + const SparseMatrix* A, + const double* D, + const double* b, + const double* x, + int num_eliminate_blocks) { CHECK_NOTNULL(A); Matrix AA; A->ToDenseMatrix(&AA); @@ -601,13 +602,13 @@ static bool DumpLinearLeastSquaresProblemToConsole(const string& directory, }; #ifndef CERES_NO_PROTOCOL_BUFFERS -static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, - int iteration, - const SparseMatrix* A, - const double* D, - const double* b, - const double* x, - int num_eliminate_blocks) { +bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, + int iteration, + const SparseMatrix* A, + const double* D, + const double* b, + const double* x, + int num_eliminate_blocks) { CHECK_NOTNULL(A); LinearLeastSquaresProblemProto lsqp; A->ToProto(lsqp.mutable_a()); @@ -641,13 +642,13 @@ static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& director return true; } #else -static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, - int iteration, - const SparseMatrix* A, - const double* D, - const double* b, - const double* x, - int num_eliminate_blocks) { +bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, + int iteration, + const SparseMatrix* A, + const double* D, + const double* b, + const double* x, + int num_eliminate_blocks) { LOG(ERROR) << "Dumping least squares problems is only " << "supported when Ceres is compiled with " << "protocol buffer support."; @@ -655,9 +656,9 @@ static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& director } #endif -static void WriteArrayToFileOrDie(const string& filename, - const double* x, - const int size) { +void WriteArrayToFileOrDie(const string& filename, + const double* x, + const int size) { CHECK_NOTNULL(x); VLOG(2) << "Writing array to: " << filename; FILE* fptr = fopen(filename.c_str(), "w"); @@ -668,13 +669,13 @@ static void WriteArrayToFileOrDie(const string& filename, fclose(fptr); } -static bool DumpLinearLeastSquaresProblemToTextFile(const string& directory, - int iteration, - const SparseMatrix* A, - const double* D, - const double* b, - const double* x, - int num_eliminate_blocks) { +bool DumpLinearLeastSquaresProblemToTextFile(const string& directory, + int iteration, + const SparseMatrix* A, + const double* D, + const double* b, + const double* x, + int num_eliminate_blocks) { CHECK_NOTNULL(A); string format_string = JoinPath(directory, "lm_iteration_%03d"); @@ -732,9 +733,10 @@ static bool DumpLinearLeastSquaresProblemToTextFile(const string& directory, WriteStringToFileOrDie(matlab_script, matlab_filename); return true; } +} // namespace bool DumpLinearLeastSquaresProblem(const string& directory, - int iteration, + int iteration, DumpFormatType dump_format_type, const SparseMatrix* A, const double* D, @@ -742,18 +744,18 @@ bool DumpLinearLeastSquaresProblem(const string& directory, const double* x, int num_eliminate_blocks) { switch (dump_format_type) { - case (CONSOLE): + case CONSOLE: return DumpLinearLeastSquaresProblemToConsole(directory, iteration, A, D, b, x, num_eliminate_blocks); - case (PROTOBUF): + case PROTOBUF: return DumpLinearLeastSquaresProblemToProtocolBuffer( directory, iteration, A, D, b, x, num_eliminate_blocks); - case (TEXTFILE): + case TEXTFILE: return DumpLinearLeastSquaresProblemToTextFile(directory, iteration, A, D, b, x, diff --git a/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.h b/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.h index 553cc0d3db3..c76ae91c7d8 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.h +++ b/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.h @@ -74,7 +74,7 @@ LinearLeastSquaresProblem* LinearLeastSquaresProblem3(); // Write the linear least squares problem to disk. The exact format // depends on dump_format_type. bool DumpLinearLeastSquaresProblem(const string& directory, - int iteration, + int iteration, DumpFormatType dump_format_type, const SparseMatrix* A, const double* D, diff --git a/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h b/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h index 31f88740b9f..a98051468e7 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h +++ b/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h @@ -35,14 +35,16 @@ #define CERES_INTERNAL_LINEAR_SOLVER_H_ #include - -#include +#include +#include #include "ceres/block_sparse_matrix.h" #include "ceres/casts.h" #include "ceres/compressed_row_sparse_matrix.h" #include "ceres/dense_sparse_matrix.h" +#include "ceres/execution_summary.h" #include "ceres/triplet_sparse_matrix.h" #include "ceres/types.h" +#include "glog/logging.h" namespace ceres { namespace internal { @@ -76,7 +78,6 @@ class LinearSolver { min_num_iterations(1), max_num_iterations(1), num_threads(1), - num_eliminate_blocks(0), residual_reset_period(10), row_block_size(Dynamic), e_block_size(Dynamic), @@ -100,15 +101,23 @@ class LinearSolver { // If possible, how many threads can the solver use. int num_threads; - // Eliminate 0 to num_eliminate_blocks - 1 from the Normal - // equations to form a schur complement. Only used by the Schur - // complement based solver. The most common use for this parameter - // is in the case of structure from motion problems where we have - // camera blocks and point blocks. Then setting the - // num_eliminate_blocks to the number of points allows the solver - // to use the Schur complement trick. For more details see the - // description of this parameter in solver.h. - int num_eliminate_blocks; + // Hints about the order in which the parameter blocks should be + // eliminated by the linear solver. + // + // For example if elimination_groups is a vector of size k, then + // the linear solver is informed that it should eliminate the + // parameter blocks 0 - elimination_groups[0] - 1 first, and then + // elimination_groups[0] - elimination_groups[1] and so on. Within + // each elimination group, the linear solver is free to choose how + // the parameter blocks are ordered. Different linear solvers have + // differing requirements on elimination_groups. + // + // The most common use is for Schur type solvers, where there + // should be at least two elimination groups and the first + // elimination group must form an independent set in the normal + // equations. The first elimination group corresponds to the + // num_eliminate_blocks in the Schur type solvers. + vector elimination_groups; // Iterative solvers, e.g. Preconditioned Conjugate Gradients // maintain a cheap estimate of the residual which may become @@ -247,6 +256,18 @@ class LinearSolver { const PerSolveOptions& per_solve_options, double* x) = 0; + // The following two methods return copies instead of references so + // that the base class implementation does not have to worry about + // life time issues. Further, these calls are not expected to be + // frequent or performance sensitive. + virtual map CallStatistics() const { + return map(); + } + + virtual map TimeStatistics() const { + return map(); + } + // Factory static LinearSolver* Create(const Options& options); }; @@ -267,18 +288,29 @@ class TypedLinearSolver : public LinearSolver { const double* b, const LinearSolver::PerSolveOptions& per_solve_options, double* x) { + ScopedExecutionTimer total_time("LinearSolver::Solve", &execution_summary_); CHECK_NOTNULL(A); CHECK_NOTNULL(b); CHECK_NOTNULL(x); return SolveImpl(down_cast(A), b, per_solve_options, x); } + virtual map CallStatistics() const { + return execution_summary_.calls(); + } + + virtual map TimeStatistics() const { + return execution_summary_.times(); + } + private: virtual LinearSolver::Summary SolveImpl( MatrixType* A, const double* b, const LinearSolver::PerSolveOptions& per_solve_options, double* x) = 0; + + ExecutionSummary execution_summary_; }; // Linear solvers that depend on acccess to the low level structure of diff --git a/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc b/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc new file mode 100644 index 00000000000..3fe113f1afb --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc @@ -0,0 +1,109 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#include "ceres/internal/eigen.h" +#include "ceres/low_rank_inverse_hessian.h" +#include "glog/logging.h" + +namespace ceres { +namespace internal { + +LowRankInverseHessian::LowRankInverseHessian(int num_parameters, + int max_num_corrections) + : num_parameters_(num_parameters), + max_num_corrections_(max_num_corrections), + num_corrections_(0), + diagonal_(1.0), + delta_x_history_(num_parameters, max_num_corrections), + delta_gradient_history_(num_parameters, max_num_corrections), + delta_x_dot_delta_gradient_(max_num_corrections) { +} + +bool LowRankInverseHessian::Update(const Vector& delta_x, + const Vector& delta_gradient) { + const double delta_x_dot_delta_gradient = delta_x.dot(delta_gradient); + if (delta_x_dot_delta_gradient <= 1e-10) { + VLOG(2) << "Skipping LBFGS Update. " << delta_x_dot_delta_gradient; + return false; + } + + if (num_corrections_ == max_num_corrections_) { + // TODO(sameeragarwal): This can be done more efficiently using + // a circular buffer/indexing scheme, but for simplicity we will + // do the expensive copy for now. + delta_x_history_.block(0, 0, num_parameters_, max_num_corrections_ - 2) = + delta_x_history_ + .block(0, 1, num_parameters_, max_num_corrections_ - 1); + + delta_gradient_history_ + .block(0, 0, num_parameters_, max_num_corrections_ - 2) = + delta_gradient_history_ + .block(0, 1, num_parameters_, max_num_corrections_ - 1); + + delta_x_dot_delta_gradient_.head(num_corrections_ - 2) = + delta_x_dot_delta_gradient_.tail(num_corrections_ - 1); + } else { + ++num_corrections_; + } + + delta_x_history_.col(num_corrections_ - 1) = delta_x; + delta_gradient_history_.col(num_corrections_ - 1) = delta_gradient; + delta_x_dot_delta_gradient_(num_corrections_ - 1) = + delta_x_dot_delta_gradient; + diagonal_ = delta_x_dot_delta_gradient / delta_gradient.squaredNorm(); + return true; +} + +void LowRankInverseHessian::RightMultiply(const double* x_ptr, + double* y_ptr) const { + ConstVectorRef gradient(x_ptr, num_parameters_); + VectorRef search_direction(y_ptr, num_parameters_); + + search_direction = gradient; + + Vector alpha(num_corrections_); + + for (int i = num_corrections_ - 1; i >= 0; --i) { + alpha(i) = delta_x_history_.col(i).dot(search_direction) / + delta_x_dot_delta_gradient_(i); + search_direction -= alpha(i) * delta_gradient_history_.col(i); + } + + search_direction *= diagonal_; + + for (int i = 0; i < num_corrections_; ++i) { + const double beta = delta_gradient_history_.col(i).dot(search_direction) / + delta_x_dot_delta_gradient_(i); + search_direction += delta_x_history_.col(i) * (alpha(i) - beta); + } +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h b/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h new file mode 100644 index 00000000000..6f3fc0c9d00 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h @@ -0,0 +1,99 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) +// +// Limited memory positive definite approximation to the inverse +// Hessian, using the LBFGS algorithm + +#ifndef CERES_INTERNAL_LOW_RANK_INVERSE_HESSIAN_H_ +#define CERES_INTERNAL_LOW_RANK_INVERSE_HESSIAN_H_ + +#include "ceres/internal/eigen.h" +#include "ceres/linear_operator.h" + +namespace ceres { +namespace internal { + +// LowRankInverseHessian is a positive definite approximation to the +// Hessian using the limited memory variant of the +// Broyden-Fletcher-Goldfarb-Shanno (BFGS)secant formula for +// approximating the Hessian. +// +// Other update rules like the Davidon-Fletcher-Powell (DFP) are +// possible, but the BFGS rule is considered the best performing one. +// +// The limited memory variant was developed by Nocedal and further +// enhanced with scaling rule by Byrd, Nocedal and Schanbel. +// +// Nocedal, J. (1980). "Updating Quasi-Newton Matrices with Limited +// Storage". Mathematics of Computation 35 (151): 773–782. +// +// Byrd, R. H.; Nocedal, J.; Schnabel, R. B. (1994). +// "Representations of Quasi-Newton Matrices and their use in +// Limited Memory Methods". Mathematical Programming 63 (4): +class LowRankInverseHessian : public LinearOperator { + public: + // num_parameters is the row/column size of the Hessian. + // max_num_corrections is the rank of the Hessian approximation. + // The approximation uses: + // 2 * max_num_corrections * num_parameters + max_num_corrections + // doubles. + LowRankInverseHessian(int num_parameters, int max_num_corrections); + virtual ~LowRankInverseHessian() {} + + // Update the low rank approximation. delta_x is the change in the + // domain of Hessian, and delta_gradient is the change in the + // gradient. The update copies the delta_x and delta_gradient + // vectors, and gets rid of the oldest delta_x and delta_gradient + // vectors if the number of corrections is already equal to + // max_num_corrections. + bool Update(const Vector& delta_x, const Vector& delta_gradient); + + // LinearOperator interface + virtual void RightMultiply(const double* x, double* y) const; + virtual void LeftMultiply(const double* x, double* y) const { + RightMultiply(x, y); + } + virtual int num_rows() const { return num_parameters_; } + virtual int num_cols() const { return num_parameters_; } + + private: + const int num_parameters_; + const int max_num_corrections_; + int num_corrections_; + double diagonal_; + Matrix delta_x_history_; + Matrix delta_gradient_history_; + Vector delta_x_dot_delta_gradient_; +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_LOW_RANK_INVERSE_HESSIAN_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/map_util.h b/extern/libmv/third_party/ceres/internal/ceres/map_util.h index ddf1252f674..929c6b36982 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/map_util.h +++ b/extern/libmv/third_party/ceres/internal/ceres/map_util.h @@ -35,6 +35,7 @@ #include #include "ceres/internal/port.h" +#include "glog/logging.h" namespace ceres { diff --git a/extern/libmv/third_party/ceres/internal/ceres/minimizer.cc b/extern/libmv/third_party/ceres/internal/ceres/minimizer.cc new file mode 100644 index 00000000000..2e2c15ac612 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/minimizer.cc @@ -0,0 +1,67 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2010, 2011, 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#include "ceres/minimizer.h" +#include "ceres/types.h" +#include "glog/logging.h" + +namespace ceres { +namespace internal { + +Minimizer::~Minimizer() {} + +bool Minimizer::RunCallbacks(const vector callbacks, + const IterationSummary& iteration_summary, + Solver::Summary* summary) { + CallbackReturnType status = SOLVER_CONTINUE; + int i = 0; + while (status == SOLVER_CONTINUE && i < callbacks.size()) { + status = (*callbacks[i])(iteration_summary); + ++i; + } + switch (status) { + case SOLVER_CONTINUE: + return true; + case SOLVER_TERMINATE_SUCCESSFULLY: + summary->termination_type = USER_SUCCESS; + VLOG(1) << "Terminating: User callback returned USER_SUCCESS."; + return false; + case SOLVER_ABORT: + summary->termination_type = USER_ABORT; + VLOG(1) << "Terminating: User callback returned USER_ABORT."; + return false; + default: + LOG(FATAL) << "Unknown type of user callback status"; + } + return false; +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/minimizer.h b/extern/libmv/third_party/ceres/internal/ceres/minimizer.h index cfc98a3ebd0..708974d63c2 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/minimizer.h +++ b/extern/libmv/third_party/ceres/internal/ceres/minimizer.h @@ -32,8 +32,9 @@ #define CERES_INTERNAL_MINIMIZER_H_ #include -#include "ceres/solver.h" +#include "ceres/internal/port.h" #include "ceres/iteration_callback.h" +#include "ceres/solver.h" namespace ceres { namespace internal { @@ -59,6 +60,7 @@ class Minimizer { } void Init(const Solver::Options& options) { + num_threads = options.num_threads; max_num_iterations = options.max_num_iterations; max_solver_time_in_seconds = options.max_solver_time_in_seconds; max_step_solver_retries = 5; @@ -74,18 +76,24 @@ class Minimizer { lsqp_dump_directory = options.lsqp_dump_directory; lsqp_iterations_to_dump = options.lsqp_iterations_to_dump; lsqp_dump_format_type = options.lsqp_dump_format_type; - num_eliminate_blocks = options.num_eliminate_blocks; max_num_consecutive_invalid_steps = options.max_num_consecutive_invalid_steps; min_trust_region_radius = options.min_trust_region_radius; + line_search_direction_type = options.line_search_direction_type; + line_search_type = options.line_search_type; + nonlinear_conjugate_gradient_type = + options.nonlinear_conjugate_gradient_type; + max_lbfgs_rank = options.max_lbfgs_rank; evaluator = NULL; trust_region_strategy = NULL; jacobian = NULL; callbacks = options.callbacks; + inner_iteration_minimizer = NULL; } int max_num_iterations; double max_solver_time_in_seconds; + int num_threads; // Number of times the linear solver should be retried in case of // numerical failure. The retries are done by exponentially scaling up @@ -104,9 +112,12 @@ class Minimizer { vector lsqp_iterations_to_dump; DumpFormatType lsqp_dump_format_type; string lsqp_dump_directory; - int num_eliminate_blocks; int max_num_consecutive_invalid_steps; int min_trust_region_radius; + LineSearchDirectionType line_search_direction_type; + LineSearchType line_search_type; + NonlinearConjugateGradientType nonlinear_conjugate_gradient_type; + int max_lbfgs_rank; // List of callbacks that are executed by the Minimizer at the end // of each iteration. @@ -128,10 +139,15 @@ class Minimizer { // and will remain constant for the life time of the // optimization. The Options struct does not own this pointer. SparseMatrix* jacobian; + + Minimizer* inner_iteration_minimizer; }; - virtual ~Minimizer() {} + static bool RunCallbacks(const vector callbacks, + const IterationSummary& iteration_summary, + Solver::Summary* summary); + virtual ~Minimizer(); // Note: The minimizer is expected to update the state of the // parameters array every iteration. This is required for the // StateUpdatingCallback to work. diff --git a/extern/libmv/third_party/ceres/internal/ceres/mutex.h b/extern/libmv/third_party/ceres/internal/ceres/mutex.h index 5090a71b78d..410748ff0ab 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/mutex.h +++ b/extern/libmv/third_party/ceres/internal/ceres/mutex.h @@ -107,10 +107,12 @@ # define _WIN32_WINNT 0x0400 # endif # endif +// Unfortunately, windows.h defines a bunch of macros with common +// names. Two in particular need avoiding: ERROR and min/max. // To avoid macro definition of ERROR. -# define CERES_NOGDI +# define NOGDI // To avoid macro definition of min/max. -# define CERES_NOMINMAX +# define NOMINMAX # include typedef CRITICAL_SECTION MutexType; #elif defined(CERES_HAVE_PTHREAD) && defined(CERES_HAVE_RWLOCK) diff --git a/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h b/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h index f20805ca873..b1e8d938b8a 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h +++ b/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h @@ -1,5 +1,5 @@ // Ceres Solver - A fast non-linear least squares minimizer -// Copyright 2010, 2011, 2012 Google Inc. All rights reserved. +// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved. // http://code.google.com/p/ceres-solver/ // // Redistribution and use in source and binary forms, with or without @@ -34,6 +34,7 @@ #include #include #include "ceres/array_utils.h" +#include "ceres/collections_port.h" #include "ceres/integral_types.h" #include "ceres/internal/eigen.h" #include "ceres/internal/port.h" @@ -46,6 +47,7 @@ namespace ceres { namespace internal { class ProblemImpl; +class ResidualBlock; // The parameter block encodes the location of the user's original value, and // also the "current state" of the parameter. The evaluator uses whatever is in @@ -58,13 +60,29 @@ class ProblemImpl; // responsible for the proper disposal of the local parameterization. class ParameterBlock { public: - ParameterBlock(double* user_state, int size) { - Init(user_state, size, NULL); + // TODO(keir): Decide what data structure is best here. Should this be a set? + // Probably not, because sets are memory inefficient. However, if it's a + // vector, you can get into pathological linear performance when removing a + // residual block from a problem where all the residual blocks depend on one + // parameter; for example, shared focal length in a bundle adjustment + // problem. It might be worth making a custom structure that is just an array + // when it is small, but transitions to a hash set when it has more elements. + // + // For now, use a hash set. + typedef HashSet ResidualBlockSet; + + // Create a parameter block with the user state, size, and index specified. + // The size is the size of the parameter block and the index is the position + // of the parameter block inside a Program (if any). + ParameterBlock(double* user_state, int size, int index) { + Init(user_state, size, index, NULL); } + ParameterBlock(double* user_state, int size, + int index, LocalParameterization* local_parameterization) { - Init(user_state, size, local_parameterization); + Init(user_state, size, index, local_parameterization); } // The size of the parameter block. @@ -187,12 +205,43 @@ class ParameterBlock { delta_offset_); } + void EnableResidualBlockDependencies() { + CHECK(residual_blocks_.get() == NULL) + << "Ceres bug: There is already a residual block collection " + << "for parameter block: " << ToString(); + residual_blocks_.reset(new ResidualBlockSet); + } + + void AddResidualBlock(ResidualBlock* residual_block) { + CHECK(residual_blocks_.get() != NULL) + << "Ceres bug: The residual block collection is null for parameter " + << "block: " << ToString(); + residual_blocks_->insert(residual_block); + } + + void RemoveResidualBlock(ResidualBlock* residual_block) { + CHECK(residual_blocks_.get() != NULL) + << "Ceres bug: The residual block collection is null for parameter " + << "block: " << ToString(); + CHECK(residual_blocks_->find(residual_block) != residual_blocks_->end()) + << "Ceres bug: Missing residual for parameter block: " << ToString(); + residual_blocks_->erase(residual_block); + } + + // This is only intended for iterating; perhaps this should only expose + // .begin() and .end(). + ResidualBlockSet* mutable_residual_blocks() { + return residual_blocks_.get(); + } + private: void Init(double* user_state, int size, + int index, LocalParameterization* local_parameterization) { user_state_ = user_state; size_ = size; + index_ = index; is_constant_ = false; state_ = user_state_; @@ -201,7 +250,6 @@ class ParameterBlock { SetParameterization(local_parameterization); } - index_ = -1; state_offset_ = -1; delta_offset_ = -1; } @@ -261,6 +309,9 @@ class ParameterBlock { // The offset of this parameter block inside a larger delta vector. int32 delta_offset_; + // If non-null, contains the residual blocks this parameter block is in. + scoped_ptr residual_blocks_; + // Necessary so ProblemImpl can clean up the parameterizations. friend class ProblemImpl; }; diff --git a/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.cc b/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.cc new file mode 100644 index 00000000000..e8f626f8e80 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.cc @@ -0,0 +1,122 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2010, 2011, 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#include "ceres/parameter_block_ordering.h" + +#include "ceres/graph.h" +#include "ceres/graph_algorithms.h" +#include "ceres/internal/scoped_ptr.h" +#include "ceres/map_util.h" +#include "ceres/parameter_block.h" +#include "ceres/program.h" +#include "ceres/residual_block.h" +#include "glog/logging.h" + +namespace ceres { +namespace internal { + +int ComputeSchurOrdering(const Program& program, + vector* ordering) { + CHECK_NOTNULL(ordering)->clear(); + + scoped_ptr > graph(CreateHessianGraph(program)); + int independent_set_size = IndependentSetOrdering(*graph, ordering); + const vector& parameter_blocks = program.parameter_blocks(); + + // Add the excluded blocks to back of the ordering vector. + for (int i = 0; i < parameter_blocks.size(); ++i) { + ParameterBlock* parameter_block = parameter_blocks[i]; + if (parameter_block->IsConstant()) { + ordering->push_back(parameter_block); + } + } + + return independent_set_size; +} + +void ComputeRecursiveIndependentSetOrdering(const Program& program, + ParameterBlockOrdering* ordering) { + CHECK_NOTNULL(ordering)->Clear(); + const vector parameter_blocks = program.parameter_blocks(); + scoped_ptr > graph(CreateHessianGraph(program)); + + int num_covered = 0; + int round = 0; + while (num_covered < parameter_blocks.size()) { + vector independent_set_ordering; + const int independent_set_size = + IndependentSetOrdering(*graph, &independent_set_ordering); + for (int i = 0; i < independent_set_size; ++i) { + ParameterBlock* parameter_block = independent_set_ordering[i]; + ordering->AddElementToGroup(parameter_block->mutable_user_state(), round); + graph->RemoveVertex(parameter_block); + } + num_covered += independent_set_size; + ++round; + } +} + +Graph* +CreateHessianGraph(const Program& program) { + Graph* graph = CHECK_NOTNULL(new Graph); + const vector& parameter_blocks = program.parameter_blocks(); + for (int i = 0; i < parameter_blocks.size(); ++i) { + ParameterBlock* parameter_block = parameter_blocks[i]; + if (!parameter_block->IsConstant()) { + graph->AddVertex(parameter_block); + } + } + + const vector& residual_blocks = program.residual_blocks(); + for (int i = 0; i < residual_blocks.size(); ++i) { + const ResidualBlock* residual_block = residual_blocks[i]; + const int num_parameter_blocks = residual_block->NumParameterBlocks(); + ParameterBlock* const* parameter_blocks = + residual_block->parameter_blocks(); + for (int j = 0; j < num_parameter_blocks; ++j) { + if (parameter_blocks[j]->IsConstant()) { + continue; + } + + for (int k = j + 1; k < num_parameter_blocks; ++k) { + if (parameter_blocks[k]->IsConstant()) { + continue; + } + + graph->AddEdge(parameter_blocks[j], parameter_blocks[k]); + } + } + } + + return graph; +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.h b/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.h new file mode 100644 index 00000000000..a5277a44c70 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.h @@ -0,0 +1,78 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2010, 2011, 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#ifndef CERES_INTERNAL_PARAMETER_BLOCK_ORDERING_H_ +#define CERES_INTERNAL_PARAMETER_BLOCK_ORDERING_H_ + +#include +#include "ceres/ordered_groups.h" +#include "ceres/graph.h" +#include "ceres/types.h" + +namespace ceres { +namespace internal { + +class Program; +class ParameterBlock; + +// Uses an approximate independent set ordering to order the parameter +// blocks of a problem so that it is suitable for use with Schur +// complement based solvers. The output variable ordering contains an +// ordering of the parameter blocks and the return value is size of +// the independent set or the number of e_blocks (see +// schur_complement_solver.h for an explanation). Constant parameters +// are added to the end. +// +// The ordering vector has the structure +// +// ordering = [independent set, +// complement of the independent set, +// fixed blocks] +int ComputeSchurOrdering(const Program& program, + vector* ordering); + +// Use an approximate independent set ordering to decompose the +// parameter blocks of a problem in a sequence of independent +// sets. The ordering covers all the non-constant parameter blocks in +// the program. +void ComputeRecursiveIndependentSetOrdering(const Program& program, + ParameterBlockOrdering* ordering); + +// Builds a graph on the parameter blocks of a Problem, whose +// structure reflects the sparsity structure of the Hessian. Each +// vertex corresponds to a parameter block in the Problem except for +// parameter blocks that are marked constant. An edge connects two +// parameter blocks, if they co-occur in a residual block. +Graph* CreateHessianGraph(const Program& program); + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_PARAMETER_BLOCK_ORDERING_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/polynomial.cc b/extern/libmv/third_party/ceres/internal/ceres/polynomial.cc new file mode 100644 index 00000000000..3238b89670e --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/polynomial.cc @@ -0,0 +1,319 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: moll.markus@arcor.de (Markus Moll) +// sameeragarwal@google.com (Sameer Agarwal) + +#include "ceres/polynomial.h" + +#include +#include +#include + +#include "Eigen/Dense" +#include "ceres/internal/port.h" +#include "glog/logging.h" + +namespace ceres { +namespace internal { +namespace { + +// Balancing function as described by B. N. Parlett and C. Reinsch, +// "Balancing a Matrix for Calculation of Eigenvalues and Eigenvectors". +// In: Numerische Mathematik, Volume 13, Number 4 (1969), 293-304, +// Springer Berlin / Heidelberg. DOI: 10.1007/BF02165404 +void BalanceCompanionMatrix(Matrix* companion_matrix_ptr) { + CHECK_NOTNULL(companion_matrix_ptr); + Matrix& companion_matrix = *companion_matrix_ptr; + Matrix companion_matrix_offdiagonal = companion_matrix; + companion_matrix_offdiagonal.diagonal().setZero(); + + const int degree = companion_matrix.rows(); + + // gamma <= 1 controls how much a change in the scaling has to + // lower the 1-norm of the companion matrix to be accepted. + // + // gamma = 1 seems to lead to cycles (numerical issues?), so + // we set it slightly lower. + const double gamma = 0.9; + + // Greedily scale row/column pairs until there is no change. + bool scaling_has_changed; + do { + scaling_has_changed = false; + + for (int i = 0; i < degree; ++i) { + const double row_norm = companion_matrix_offdiagonal.row(i).lpNorm<1>(); + const double col_norm = companion_matrix_offdiagonal.col(i).lpNorm<1>(); + + // Decompose row_norm/col_norm into mantissa * 2^exponent, + // where 0.5 <= mantissa < 1. Discard mantissa (return value + // of frexp), as only the exponent is needed. + int exponent = 0; + std::frexp(row_norm / col_norm, &exponent); + exponent /= 2; + + if (exponent != 0) { + const double scaled_col_norm = std::ldexp(col_norm, exponent); + const double scaled_row_norm = std::ldexp(row_norm, -exponent); + if (scaled_col_norm + scaled_row_norm < gamma * (col_norm + row_norm)) { + // Accept the new scaling. (Multiplication by powers of 2 should not + // introduce rounding errors (ignoring non-normalized numbers and + // over- or underflow)) + scaling_has_changed = true; + companion_matrix_offdiagonal.row(i) *= std::ldexp(1.0, -exponent); + companion_matrix_offdiagonal.col(i) *= std::ldexp(1.0, exponent); + } + } + } + } while (scaling_has_changed); + + companion_matrix_offdiagonal.diagonal() = companion_matrix.diagonal(); + companion_matrix = companion_matrix_offdiagonal; + VLOG(3) << "Balanced companion matrix is\n" << companion_matrix; +} + +void BuildCompanionMatrix(const Vector& polynomial, + Matrix* companion_matrix_ptr) { + CHECK_NOTNULL(companion_matrix_ptr); + Matrix& companion_matrix = *companion_matrix_ptr; + + const int degree = polynomial.size() - 1; + + companion_matrix.resize(degree, degree); + companion_matrix.setZero(); + companion_matrix.diagonal(-1).setOnes(); + companion_matrix.col(degree - 1) = -polynomial.reverse().head(degree); +} + +// Remove leading terms with zero coefficients. +Vector RemoveLeadingZeros(const Vector& polynomial_in) { + int i = 0; + while (i < (polynomial_in.size() - 1) && polynomial_in(i) == 0.0) { + ++i; + } + return polynomial_in.tail(polynomial_in.size() - i); +} +} // namespace + +bool FindPolynomialRoots(const Vector& polynomial_in, + Vector* real, + Vector* imaginary) { + if (polynomial_in.size() == 0) { + LOG(ERROR) << "Invalid polynomial of size 0 passed to FindPolynomialRoots"; + return false; + } + + Vector polynomial = RemoveLeadingZeros(polynomial_in); + const int degree = polynomial.size() - 1; + + // Is the polynomial constant? + if (degree == 0) { + LOG(WARNING) << "Trying to extract roots from a constant " + << "polynomial in FindPolynomialRoots"; + return true; + } + + // Divide by leading term + const double leading_term = polynomial(0); + polynomial /= leading_term; + + // Separately handle linear polynomials. + if (degree == 1) { + if (real != NULL) { + real->resize(1); + (*real)(0) = -polynomial(1); + } + if (imaginary != NULL) { + imaginary->resize(1); + imaginary->setZero(); + } + } + + // The degree is now known to be at least 2. + // Build and balance the companion matrix to the polynomial. + Matrix companion_matrix(degree, degree); + BuildCompanionMatrix(polynomial, &companion_matrix); + BalanceCompanionMatrix(&companion_matrix); + + // Find its (complex) eigenvalues. + Eigen::EigenSolver solver(companion_matrix, false); + if (solver.info() != Eigen::Success) { + LOG(ERROR) << "Failed to extract eigenvalues from companion matrix."; + return false; + } + + // Output roots + if (real != NULL) { + *real = solver.eigenvalues().real(); + } else { + LOG(WARNING) << "NULL pointer passed as real argument to " + << "FindPolynomialRoots. Real parts of the roots will not " + << "be returned."; + } + if (imaginary != NULL) { + *imaginary = solver.eigenvalues().imag(); + } + return true; +} + +Vector DifferentiatePolynomial(const Vector& polynomial) { + const int degree = polynomial.rows() - 1; + CHECK_GE(degree, 0); + + // Degree zero polynomials are constants, and their derivative does + // not result in a smaller degree polynomial, just a degree zero + // polynomial with value zero. + if (degree == 0) { + return Eigen::VectorXd::Zero(1); + } + + Vector derivative(degree); + for (int i = 0; i < degree; ++i) { + derivative(i) = (degree - i) * polynomial(i); + } + + return derivative; +} + +void MinimizePolynomial(const Vector& polynomial, + const double x_min, + const double x_max, + double* optimal_x, + double* optimal_value) { + // Find the minimum of the polynomial at the two ends. + // + // We start by inspecting the middle of the interval. Technically + // this is not needed, but we do this to make this code as close to + // the minFunc package as possible. + *optimal_x = (x_min + x_max) / 2.0; + *optimal_value = EvaluatePolynomial(polynomial, *optimal_x); + + const double x_min_value = EvaluatePolynomial(polynomial, x_min); + if (x_min_value < *optimal_value) { + *optimal_value = x_min_value; + *optimal_x = x_min; + } + + const double x_max_value = EvaluatePolynomial(polynomial, x_max); + if (x_max_value < *optimal_value) { + *optimal_value = x_max_value; + *optimal_x = x_max; + } + + // If the polynomial is linear or constant, we are done. + if (polynomial.rows() <= 2) { + return; + } + + const Vector derivative = DifferentiatePolynomial(polynomial); + Vector roots_real; + if (!FindPolynomialRoots(derivative, &roots_real, NULL)) { + LOG(WARNING) << "Unable to find the critical points of " + << "the interpolating polynomial."; + return; + } + + // This is a bit of an overkill, as some of the roots may actually + // have a complex part, but its simpler to just check these values. + for (int i = 0; i < roots_real.rows(); ++i) { + const double root = roots_real(i); + if ((root < x_min) || (root > x_max)) { + continue; + } + + const double value = EvaluatePolynomial(polynomial, root); + if (value < *optimal_value) { + *optimal_value = value; + *optimal_x = root; + } + } +} + +Vector FindInterpolatingPolynomial(const vector& samples) { + const int num_samples = samples.size(); + int num_constraints = 0; + for (int i = 0; i < num_samples; ++i) { + if (samples[i].value_is_valid) { + ++num_constraints; + } + if (samples[i].gradient_is_valid) { + ++num_constraints; + } + } + + const int degree = num_constraints - 1; + Matrix lhs = Matrix::Zero(num_constraints, num_constraints); + Vector rhs = Vector::Zero(num_constraints); + + int row = 0; + for (int i = 0; i < num_samples; ++i) { + const FunctionSample& sample = samples[i]; + if (sample.value_is_valid) { + for (int j = 0; j <= degree; ++j) { + lhs(row, j) = pow(sample.x, degree - j); + } + rhs(row) = sample.value; + ++row; + } + + if (sample.gradient_is_valid) { + for (int j = 0; j < degree; ++j) { + lhs(row, j) = (degree - j) * pow(sample.x, degree - j - 1); + } + rhs(row) = sample.gradient; + ++row; + } + } + + return lhs.fullPivLu().solve(rhs); +} + +void MinimizeInterpolatingPolynomial(const vector& samples, + double x_min, + double x_max, + double* optimal_x, + double* optimal_value) { + const Vector polynomial = FindInterpolatingPolynomial(samples); + MinimizePolynomial(polynomial, x_min, x_max, optimal_x, optimal_value); + for (int i = 0; i < samples.size(); ++i) { + const FunctionSample& sample = samples[i]; + if ((sample.x < x_min) || (sample.x > x_max)) { + continue; + } + + const double value = EvaluatePolynomial(polynomial, sample.x); + if (value < *optimal_value) { + *optimal_x = sample.x; + *optimal_value = value; + } + } +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/polynomial.h b/extern/libmv/third_party/ceres/internal/ceres/polynomial.h new file mode 100644 index 00000000000..42ffdcb13c5 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/polynomial.h @@ -0,0 +1,134 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: moll.markus@arcor.de (Markus Moll) +// sameeragarwal@google.com (Sameer Agarwal) + +#ifndef CERES_INTERNAL_POLYNOMIAL_SOLVER_H_ +#define CERES_INTERNAL_POLYNOMIAL_SOLVER_H_ + +#include +#include "ceres/internal/eigen.h" +#include "ceres/internal/port.h" + +namespace ceres { +namespace internal { + +// All polynomials are assumed to be the form +// +// sum_{i=0}^N polynomial(i) x^{N-i}. +// +// and are given by a vector of coefficients of size N + 1. + +// Evaluate the polynomial at x using the Horner scheme. +inline double EvaluatePolynomial(const Vector& polynomial, double x) { + double v = 0.0; + for (int i = 0; i < polynomial.size(); ++i) { + v = v * x + polynomial(i); + } + return v; +} + +// Use the companion matrix eigenvalues to determine the roots of the +// polynomial. +// +// This function returns true on success, false otherwise. +// Failure indicates that the polynomial is invalid (of size 0) or +// that the eigenvalues of the companion matrix could not be computed. +// On failure, a more detailed message will be written to LOG(ERROR). +// If real is not NULL, the real parts of the roots will be returned in it. +// Likewise, if imaginary is not NULL, imaginary parts will be returned in it. +bool FindPolynomialRoots(const Vector& polynomial, + Vector* real, + Vector* imaginary); + +// Return the derivative of the given polynomial. It is assumed that +// the input polynomial is at least of degree zero. +Vector DifferentiatePolynomial(const Vector& polynomial); + +// Find the minimum value of the polynomial in the interval [x_min, +// x_max]. The minimum is obtained by computing all the roots of the +// derivative of the input polynomial. All real roots within the +// interval [x_min, x_max] are considered as well as the end points +// x_min and x_max. Since polynomials are differentiable functions, +// this ensures that the true minimum is found. +void MinimizePolynomial(const Vector& polynomial, + double x_min, + double x_max, + double* optimal_x, + double* optimal_value); + +// Structure for storing sample values of a function. +// +// Clients can use this struct to communicate the value of the +// function and or its gradient at a given point x. +struct FunctionSample { + FunctionSample() + : x(0.0), + value(0.0), + value_is_valid(false), + gradient(0.0), + gradient_is_valid(false) { + } + + double x; + double value; // value = f(x) + bool value_is_valid; + double gradient; // gradient = f'(x) + bool gradient_is_valid; +}; + +// Given a set of function value and/or gradient samples, find a +// polynomial whose value and gradients are exactly equal to the ones +// in samples. +// +// Generally speaking, +// +// degree = # values + # gradients - 1 +// +// Of course its possible to sample a polynomial any number of times, +// in which case, generally speaking the spurious higher order +// coefficients will be zero. +Vector FindInterpolatingPolynomial(const vector& samples); + +// Interpolate the function described by samples with a polynomial, +// and minimize it on the interval [x_min, x_max]. Depending on the +// input samples, it is possible that the interpolation or the root +// finding algorithms may fail due to numerical difficulties. But the +// function is guaranteed to return its best guess of an answer, by +// considering the samples and the end points as possible solutions. +void MinimizeInterpolatingPolynomial(const vector& samples, + double x_min, + double x_max, + double* optimal_x, + double* optimal_value); + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_POLYNOMIAL_SOLVER_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.cc deleted file mode 100644 index 20c01566a89..00000000000 --- a/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.cc +++ /dev/null @@ -1,184 +0,0 @@ -// Ceres Solver - A fast non-linear least squares minimizer -// Copyright 2012 Google Inc. All rights reserved. -// http://code.google.com/p/ceres-solver/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of Google Inc. nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Author: moll.markus@arcor.de (Markus Moll) - -#include "ceres/polynomial_solver.h" - -#include -#include -#include "Eigen/Dense" -#include "ceres/internal/port.h" -#include "glog/logging.h" - -namespace ceres { -namespace internal { -namespace { - -// Balancing function as described by B. N. Parlett and C. Reinsch, -// "Balancing a Matrix for Calculation of Eigenvalues and Eigenvectors". -// In: Numerische Mathematik, Volume 13, Number 4 (1969), 293-304, -// Springer Berlin / Heidelberg. DOI: 10.1007/BF02165404 -void BalanceCompanionMatrix(Matrix* companion_matrix_ptr) { - CHECK_NOTNULL(companion_matrix_ptr); - Matrix& companion_matrix = *companion_matrix_ptr; - Matrix companion_matrix_offdiagonal = companion_matrix; - companion_matrix_offdiagonal.diagonal().setZero(); - - const int degree = companion_matrix.rows(); - - // gamma <= 1 controls how much a change in the scaling has to - // lower the 1-norm of the companion matrix to be accepted. - // - // gamma = 1 seems to lead to cycles (numerical issues?), so - // we set it slightly lower. - const double gamma = 0.9; - - // Greedily scale row/column pairs until there is no change. - bool scaling_has_changed; - do { - scaling_has_changed = false; - - for (int i = 0; i < degree; ++i) { - const double row_norm = companion_matrix_offdiagonal.row(i).lpNorm<1>(); - const double col_norm = companion_matrix_offdiagonal.col(i).lpNorm<1>(); - - // Decompose row_norm/col_norm into mantissa * 2^exponent, - // where 0.5 <= mantissa < 1. Discard mantissa (return value - // of frexp), as only the exponent is needed. - int exponent = 0; - std::frexp(row_norm / col_norm, &exponent); - exponent /= 2; - - if (exponent != 0) { - const double scaled_col_norm = std::ldexp(col_norm, exponent); - const double scaled_row_norm = std::ldexp(row_norm, -exponent); - if (scaled_col_norm + scaled_row_norm < gamma * (col_norm + row_norm)) { - // Accept the new scaling. (Multiplication by powers of 2 should not - // introduce rounding errors (ignoring non-normalized numbers and - // over- or underflow)) - scaling_has_changed = true; - companion_matrix_offdiagonal.row(i) *= std::ldexp(1.0, -exponent); - companion_matrix_offdiagonal.col(i) *= std::ldexp(1.0, exponent); - } - } - } - } while (scaling_has_changed); - - companion_matrix_offdiagonal.diagonal() = companion_matrix.diagonal(); - companion_matrix = companion_matrix_offdiagonal; - VLOG(3) << "Balanced companion matrix is\n" << companion_matrix; -} - -void BuildCompanionMatrix(const Vector& polynomial, - Matrix* companion_matrix_ptr) { - CHECK_NOTNULL(companion_matrix_ptr); - Matrix& companion_matrix = *companion_matrix_ptr; - - const int degree = polynomial.size() - 1; - - companion_matrix.resize(degree, degree); - companion_matrix.setZero(); - companion_matrix.diagonal(-1).setOnes(); - companion_matrix.col(degree - 1) = -polynomial.reverse().head(degree); -} - -// Remove leading terms with zero coefficients. -Vector RemoveLeadingZeros(const Vector& polynomial_in) { - int i = 0; - while (i < (polynomial_in.size() - 1) && polynomial_in(i) == 0.0) { - ++i; - } - return polynomial_in.tail(polynomial_in.size() - i); -} -} // namespace - -bool FindPolynomialRoots(const Vector& polynomial_in, - Vector* real, - Vector* imaginary) { - if (polynomial_in.size() == 0) { - LOG(ERROR) << "Invalid polynomial of size 0 passed to FindPolynomialRoots"; - return false; - } - - Vector polynomial = RemoveLeadingZeros(polynomial_in); - const int degree = polynomial.size() - 1; - - // Is the polynomial constant? - if (degree == 0) { - LOG(WARNING) << "Trying to extract roots from a constant " - << "polynomial in FindPolynomialRoots"; - return true; - } - - // Divide by leading term - const double leading_term = polynomial(0); - polynomial /= leading_term; - - // Separately handle linear polynomials. - if (degree == 1) { - if (real != NULL) { - real->resize(1); - (*real)(0) = -polynomial(1); - } - if (imaginary != NULL) { - imaginary->resize(1); - imaginary->setZero(); - } - } - - // The degree is now known to be at least 2. - // Build and balance the companion matrix to the polynomial. - Matrix companion_matrix(degree, degree); - BuildCompanionMatrix(polynomial, &companion_matrix); - BalanceCompanionMatrix(&companion_matrix); - - // Find its (complex) eigenvalues. - Eigen::EigenSolver solver(companion_matrix, - Eigen::EigenvaluesOnly); - if (solver.info() != Eigen::Success) { - LOG(ERROR) << "Failed to extract eigenvalues from companion matrix."; - return false; - } - - // Output roots - if (real != NULL) { - *real = solver.eigenvalues().real(); - } else { - LOG(WARNING) << "NULL pointer passed as real argument to " - << "FindPolynomialRoots. Real parts of the roots will not " - << "be returned."; - } - if (imaginary != NULL) { - *imaginary = solver.eigenvalues().imag(); - } - return true; -} - -} // namespace internal -} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.h b/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.h deleted file mode 100644 index 1cf07ddb549..00000000000 --- a/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.h +++ /dev/null @@ -1,65 +0,0 @@ -// Ceres Solver - A fast non-linear least squares minimizer -// Copyright 2012 Google Inc. All rights reserved. -// http://code.google.com/p/ceres-solver/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of Google Inc. nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Author: moll.markus@arcor.de (Markus Moll) - -#ifndef CERES_INTERNAL_POLYNOMIAL_SOLVER_H_ -#define CERES_INTERNAL_POLYNOMIAL_SOLVER_H_ - -#include "ceres/internal/eigen.h" - -namespace ceres { -namespace internal { - -// Use the companion matrix eigenvalues to determine the roots of the polynomial -// -// sum_{i=0}^N polynomial(i) x^{N-i}. -// -// This function returns true on success, false otherwise. -// Failure indicates that the polynomial is invalid (of size 0) or -// that the eigenvalues of the companion matrix could not be computed. -// On failure, a more detailed message will be written to LOG(ERROR). -// If real is not NULL, the real parts of the roots will be returned in it. -// Likewise, if imaginary is not NULL, imaginary parts will be returned in it. -bool FindPolynomialRoots(const Vector& polynomial, - Vector* real, - Vector* imaginary); - -// Evaluate the polynomial at x using the Horner scheme. -inline double EvaluatePolynomial(const Vector& polynomial, double x) { - double v = 0.0; - for (int i = 0; i < polynomial.size(); ++i) { - v = v * x + polynomial(i); - } - return v; -} - -} // namespace internal -} // namespace ceres - -#endif // CERES_INTERNAL_POLYNOMIAL_SOLVER_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/preconditioner.cc b/extern/libmv/third_party/ceres/internal/ceres/preconditioner.cc new file mode 100644 index 00000000000..05e539f9fb1 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/preconditioner.cc @@ -0,0 +1,63 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2013 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#include "ceres/preconditioner.h" +#include "glog/logging.h" + +namespace ceres { +namespace internal { + +Preconditioner::~Preconditioner() { +} + +SparseMatrixPreconditionerWrapper::SparseMatrixPreconditionerWrapper( + const SparseMatrix* matrix) + : matrix_(CHECK_NOTNULL(matrix)) { +} + +SparseMatrixPreconditionerWrapper::~SparseMatrixPreconditionerWrapper() { +} + +bool SparseMatrixPreconditionerWrapper::Update(const BlockSparseMatrixBase& A, + const double* D) { + return true; +} + +void SparseMatrixPreconditionerWrapper::RightMultiply(const double* x, + double* y) const { + matrix_->RightMultiply(x, y); +} + +int SparseMatrixPreconditionerWrapper::num_rows() const { + return matrix_->num_rows(); +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/preconditioner.h b/extern/libmv/third_party/ceres/internal/ceres/preconditioner.h new file mode 100644 index 00000000000..5bb077e0e33 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/preconditioner.h @@ -0,0 +1,148 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2013 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#ifndef CERES_INTERNAL_PRECONDITIONER_H_ +#define CERES_INTERNAL_PRECONDITIONER_H_ + +#include +#include "ceres/linear_operator.h" +#include "ceres/sparse_matrix.h" + +namespace ceres { +namespace internal { + +class BlockSparseMatrixBase; +class SparseMatrix; + +class Preconditioner : public LinearOperator { + public: + struct Options { + Options() + : type(JACOBI), + sparse_linear_algebra_library(SUITE_SPARSE), + use_block_amd(true), + num_threads(1), + row_block_size(Dynamic), + e_block_size(Dynamic), + f_block_size(Dynamic) { + } + + PreconditionerType type; + + SparseLinearAlgebraLibraryType sparse_linear_algebra_library; + + // See solver.h for explanation of this option. + bool use_block_amd; + + // If possible, how many threads the preconditioner can use. + int num_threads; + + // Hints about the order in which the parameter blocks should be + // eliminated by the linear solver. + // + // For example if elimination_groups is a vector of size k, then + // the linear solver is informed that it should eliminate the + // parameter blocks 0 ... elimination_groups[0] - 1 first, and + // then elimination_groups[0] ... elimination_groups[1] and so + // on. Within each elimination group, the linear solver is free to + // choose how the parameter blocks are ordered. Different linear + // solvers have differing requirements on elimination_groups. + // + // The most common use is for Schur type solvers, where there + // should be at least two elimination groups and the first + // elimination group must form an independent set in the normal + // equations. The first elimination group corresponds to the + // num_eliminate_blocks in the Schur type solvers. + vector elimination_groups; + + // If the block sizes in a BlockSparseMatrix are fixed, then in + // some cases the Schur complement based solvers can detect and + // specialize on them. + // + // It is expected that these parameters are set programmatically + // rather than manually. + // + // Please see schur_complement_solver.h and schur_eliminator.h for + // more details. + int row_block_size; + int e_block_size; + int f_block_size; + }; + + virtual ~Preconditioner(); + + // Update the numerical value of the preconditioner for the linear + // system: + // + // | A | x = |b| + // |diag(D)| |0| + // + // for some vector b. It is important that the matrix A have the + // same block structure as the one used to construct this object. + // + // D can be NULL, in which case its interpreted as a diagonal matrix + // of size zero. + virtual bool Update(const BlockSparseMatrixBase& A, const double* D) = 0; + + // LinearOperator interface. Since the operator is symmetric, + // LeftMultiply and num_cols are just calls to RightMultiply and + // num_rows respectively. Update() must be called before + // RightMultiply can be called. + virtual void RightMultiply(const double* x, double* y) const = 0; + virtual void LeftMultiply(const double* x, double* y) const { + return RightMultiply(x, y); + } + + virtual int num_rows() const = 0; + virtual int num_cols() const { + return num_rows(); + } +}; + +// Wrap a SparseMatrix object as a preconditioner. +class SparseMatrixPreconditionerWrapper : public Preconditioner { + public: + // Wrapper does NOT take ownership of the matrix pointer. + explicit SparseMatrixPreconditionerWrapper(const SparseMatrix* matrix); + virtual ~SparseMatrixPreconditionerWrapper(); + + // Preconditioner interface + virtual bool Update(const BlockSparseMatrixBase& A, const double* D); + virtual void RightMultiply(const double* x, double* y) const; + virtual int num_rows() const; + + private: + const SparseMatrix* matrix_; +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_PRECONDITIONER_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/problem.cc b/extern/libmv/third_party/ceres/internal/ceres/problem.cc index b8c25d9db84..43e78835b15 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/problem.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/problem.cc @@ -32,12 +32,11 @@ #include "ceres/problem.h" #include +#include "ceres/crs_matrix.h" #include "ceres/problem_impl.h" namespace ceres { -class ResidualBlock; - Problem::Problem() : problem_impl_(new internal::ProblemImpl) {} Problem::Problem(const Problem::Options& options) : problem_impl_(new internal::ProblemImpl(options)) {} @@ -106,6 +105,47 @@ ResidualBlockId Problem::AddResidualBlock( x0, x1, x2, x3, x4, x5); } +ResidualBlockId Problem::AddResidualBlock( + CostFunction* cost_function, + LossFunction* loss_function, + double* x0, double* x1, double* x2, double* x3, double* x4, double* x5, + double* x6) { + return problem_impl_->AddResidualBlock(cost_function, + loss_function, + x0, x1, x2, x3, x4, x5, x6); +} + +ResidualBlockId Problem::AddResidualBlock( + CostFunction* cost_function, + LossFunction* loss_function, + double* x0, double* x1, double* x2, double* x3, double* x4, double* x5, + double* x6, double* x7) { + return problem_impl_->AddResidualBlock(cost_function, + loss_function, + x0, x1, x2, x3, x4, x5, x6, x7); +} + +ResidualBlockId Problem::AddResidualBlock( + CostFunction* cost_function, + LossFunction* loss_function, + double* x0, double* x1, double* x2, double* x3, double* x4, double* x5, + double* x6, double* x7, double* x8) { + return problem_impl_->AddResidualBlock(cost_function, + loss_function, + x0, x1, x2, x3, x4, x5, x6, x7, x8); +} + +ResidualBlockId Problem::AddResidualBlock( + CostFunction* cost_function, + LossFunction* loss_function, + double* x0, double* x1, double* x2, double* x3, double* x4, double* x5, + double* x6, double* x7, double* x8, double* x9) { + return problem_impl_->AddResidualBlock( + cost_function, + loss_function, + x0, x1, x2, x3, x4, x5, x6, x7, x8, x9); +} + void Problem::AddParameterBlock(double* values, int size) { problem_impl_->AddParameterBlock(values, size); } @@ -116,6 +156,14 @@ void Problem::AddParameterBlock(double* values, problem_impl_->AddParameterBlock(values, size, local_parameterization); } +void Problem::RemoveResidualBlock(ResidualBlockId residual_block) { + problem_impl_->RemoveResidualBlock(residual_block); +} + +void Problem::RemoveParameterBlock(double* values) { + problem_impl_->RemoveParameterBlock(values); +} + void Problem::SetParameterBlockConstant(double* values) { problem_impl_->SetParameterBlockConstant(values); } @@ -130,6 +178,18 @@ void Problem::SetParameterization( problem_impl_->SetParameterization(values, local_parameterization); } +bool Problem::Evaluate(const EvaluateOptions& evaluate_options, + double* cost, + vector* residuals, + vector* gradient, + CRSMatrix* jacobian) { + return problem_impl_->Evaluate(evaluate_options, + cost, + residuals, + gradient, + jacobian); +} + int Problem::NumParameterBlocks() const { return problem_impl_->NumParameterBlocks(); } diff --git a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc index c186f527be8..bc378aaafff 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc @@ -37,7 +37,11 @@ #include #include #include +#include "ceres/casts.h" +#include "ceres/compressed_row_sparse_matrix.h" #include "ceres/cost_function.h" +#include "ceres/crs_matrix.h" +#include "ceres/evaluator.h" #include "ceres/loss_function.h" #include "ceres/map_util.h" #include "ceres/parameter_block.h" @@ -73,54 +77,103 @@ static void CheckForNoAliasing(double* existing_block, << "size " << new_block_size << "."; } -static ParameterBlock* InternalAddParameterBlock( - double* values, - int size, - ParameterMap* parameter_map, - vector* parameter_blocks) { - CHECK(values) << "Null pointer passed to AddParameterBlock for a parameter " - << "with size " << size; +ParameterBlock* ProblemImpl::InternalAddParameterBlock(double* values, + int size) { + CHECK(values != NULL) << "Null pointer passed to AddParameterBlock " + << "for a parameter with size " << size; // Ignore the request if there is a block for the given pointer already. - ParameterMap::iterator it = parameter_map->find(values); - if (it != parameter_map->end()) { - int existing_size = it->second->Size(); - CHECK(size == existing_size) - << "Tried adding a parameter block with the same double pointer, " - << values << ", twice, but with different block sizes. Original " - << "size was " << existing_size << " but new size is " - << size; + ParameterMap::iterator it = parameter_block_map_.find(values); + if (it != parameter_block_map_.end()) { + if (!options_.disable_all_safety_checks) { + int existing_size = it->second->Size(); + CHECK(size == existing_size) + << "Tried adding a parameter block with the same double pointer, " + << values << ", twice, but with different block sizes. Original " + << "size was " << existing_size << " but new size is " + << size; + } return it->second; } - // Before adding the parameter block, also check that it doesn't alias any - // other parameter blocks. - if (!parameter_map->empty()) { - ParameterMap::iterator lb = parameter_map->lower_bound(values); - - // If lb is not the first block, check the previous block for aliasing. - if (lb != parameter_map->begin()) { - ParameterMap::iterator previous = lb; - --previous; - CheckForNoAliasing(previous->first, - previous->second->Size(), - values, - size); - } - // If lb is not off the end, check lb for aliasing. - if (lb != parameter_map->end()) { - CheckForNoAliasing(lb->first, - lb->second->Size(), - values, - size); + if (!options_.disable_all_safety_checks) { + // Before adding the parameter block, also check that it doesn't alias any + // other parameter blocks. + if (!parameter_block_map_.empty()) { + ParameterMap::iterator lb = parameter_block_map_.lower_bound(values); + + // If lb is not the first block, check the previous block for aliasing. + if (lb != parameter_block_map_.begin()) { + ParameterMap::iterator previous = lb; + --previous; + CheckForNoAliasing(previous->first, + previous->second->Size(), + values, + size); + } + + // If lb is not off the end, check lb for aliasing. + if (lb != parameter_block_map_.end()) { + CheckForNoAliasing(lb->first, + lb->second->Size(), + values, + size); + } } } - ParameterBlock* new_parameter_block = new ParameterBlock(values, size); - (*parameter_map)[values] = new_parameter_block; - parameter_blocks->push_back(new_parameter_block); + + // Pass the index of the new parameter block as well to keep the index in + // sync with the position of the parameter in the program's parameter vector. + ParameterBlock* new_parameter_block = + new ParameterBlock(values, size, program_->parameter_blocks_.size()); + + // For dynamic problems, add the list of dependent residual blocks, which is + // empty to start. + if (options_.enable_fast_parameter_block_removal) { + new_parameter_block->EnableResidualBlockDependencies(); + } + parameter_block_map_[values] = new_parameter_block; + program_->parameter_blocks_.push_back(new_parameter_block); return new_parameter_block; } +// Deletes the residual block in question, assuming there are no other +// references to it inside the problem (e.g. by another parameter). Referenced +// cost and loss functions are tucked away for future deletion, since it is not +// possible to know whether other parts of the problem depend on them without +// doing a full scan. +void ProblemImpl::DeleteBlock(ResidualBlock* residual_block) { + // The const casts here are legit, since ResidualBlock holds these + // pointers as const pointers but we have ownership of them and + // have the right to destroy them when the destructor is called. + if (options_.cost_function_ownership == TAKE_OWNERSHIP && + residual_block->cost_function() != NULL) { + cost_functions_to_delete_.push_back( + const_cast(residual_block->cost_function())); + } + if (options_.loss_function_ownership == TAKE_OWNERSHIP && + residual_block->loss_function() != NULL) { + loss_functions_to_delete_.push_back( + const_cast(residual_block->loss_function())); + } + delete residual_block; +} + +// Deletes the parameter block in question, assuming there are no other +// references to it inside the problem (e.g. by any residual blocks). +// Referenced parameterizations are tucked away for future deletion, since it +// is not possible to know whether other parts of the problem depend on them +// without doing a full scan. +void ProblemImpl::DeleteBlock(ParameterBlock* parameter_block) { + if (options_.local_parameterization_ownership == TAKE_OWNERSHIP && + parameter_block->local_parameterization() != NULL) { + local_parameterizations_to_delete_.push_back( + parameter_block->mutable_local_parameterization()); + } + parameter_block_map_.erase(parameter_block->mutable_user_state()); + delete parameter_block; +} + ProblemImpl::ProblemImpl() : program_(new internal::Program) {} ProblemImpl::ProblemImpl(const Problem::Options& options) : options_(options), @@ -128,48 +181,28 @@ ProblemImpl::ProblemImpl(const Problem::Options& options) ProblemImpl::~ProblemImpl() { // Collect the unique cost/loss functions and delete the residuals. - set cost_functions; - set loss_functions; + const int num_residual_blocks = program_->residual_blocks_.size(); + cost_functions_to_delete_.reserve(num_residual_blocks); + loss_functions_to_delete_.reserve(num_residual_blocks); for (int i = 0; i < program_->residual_blocks_.size(); ++i) { - ResidualBlock* residual_block = program_->residual_blocks_[i]; - - // The const casts here are legit, since ResidualBlock holds these - // pointers as const pointers but we have ownership of them and - // have the right to destroy them when the destructor is called. - if (options_.cost_function_ownership == TAKE_OWNERSHIP) { - cost_functions.insert( - const_cast(residual_block->cost_function())); - } - if (options_.loss_function_ownership == TAKE_OWNERSHIP) { - loss_functions.insert( - const_cast(residual_block->loss_function())); - } - - delete residual_block; + DeleteBlock(program_->residual_blocks_[i]); } // Collect the unique parameterizations and delete the parameters. - set local_parameterizations; for (int i = 0; i < program_->parameter_blocks_.size(); ++i) { - ParameterBlock* parameter_block = program_->parameter_blocks_[i]; - - if (options_.local_parameterization_ownership == TAKE_OWNERSHIP) { - local_parameterizations.insert(parameter_block->local_parameterization_); - } - - delete parameter_block; + DeleteBlock(program_->parameter_blocks_[i]); } // Delete the owned cost/loss functions and parameterizations. - STLDeleteContainerPointers(local_parameterizations.begin(), - local_parameterizations.end()); - STLDeleteContainerPointers(cost_functions.begin(), - cost_functions.end()); - STLDeleteContainerPointers(loss_functions.begin(), - loss_functions.end()); + STLDeleteUniqueContainerPointers(local_parameterizations_to_delete_.begin(), + local_parameterizations_to_delete_.end()); + STLDeleteUniqueContainerPointers(cost_functions_to_delete_.begin(), + cost_functions_to_delete_.end()); + STLDeleteUniqueContainerPointers(loss_functions_to_delete_.begin(), + loss_functions_to_delete_.end()); } -const ResidualBlock* ProblemImpl::AddResidualBlock( +ResidualBlock* ProblemImpl::AddResidualBlock( CostFunction* cost_function, LossFunction* loss_function, const vector& parameter_blocks) { @@ -180,25 +213,28 @@ const ResidualBlock* ProblemImpl::AddResidualBlock( // Check the sizes match. const vector& parameter_block_sizes = cost_function->parameter_block_sizes(); - CHECK_EQ(parameter_block_sizes.size(), parameter_blocks.size()) - << "Number of blocks input is different than the number of blocks " - << "that the cost function expects."; - - // Check for duplicate parameter blocks. - vector sorted_parameter_blocks(parameter_blocks); - sort(sorted_parameter_blocks.begin(), sorted_parameter_blocks.end()); - vector::const_iterator duplicate_items = - unique(sorted_parameter_blocks.begin(), - sorted_parameter_blocks.end()); - if (duplicate_items != sorted_parameter_blocks.end()) { - string blocks; - for (int i = 0; i < parameter_blocks.size(); ++i) { - blocks += internal::StringPrintf(" %p ", parameter_blocks[i]); - } - LOG(FATAL) << "Duplicate parameter blocks in a residual parameter " - << "are not allowed. Parameter block pointers: [" - << blocks << "]"; + if (!options_.disable_all_safety_checks) { + CHECK_EQ(parameter_block_sizes.size(), parameter_blocks.size()) + << "Number of blocks input is different than the number of blocks " + << "that the cost function expects."; + + // Check for duplicate parameter blocks. + vector sorted_parameter_blocks(parameter_blocks); + sort(sorted_parameter_blocks.begin(), sorted_parameter_blocks.end()); + vector::const_iterator duplicate_items = + unique(sorted_parameter_blocks.begin(), + sorted_parameter_blocks.end()); + if (duplicate_items != sorted_parameter_blocks.end()) { + string blocks; + for (int i = 0; i < parameter_blocks.size(); ++i) { + blocks += StringPrintf(" %p ", parameter_blocks[i]); + } + + LOG(FATAL) << "Duplicate parameter blocks in a residual parameter " + << "are not allowed. Parameter block pointers: [" + << blocks << "]"; + } } // Add parameter blocks and convert the double*'s to parameter blocks. @@ -206,33 +242,42 @@ const ResidualBlock* ProblemImpl::AddResidualBlock( for (int i = 0; i < parameter_blocks.size(); ++i) { parameter_block_ptrs[i] = InternalAddParameterBlock(parameter_blocks[i], - parameter_block_sizes[i], - ¶meter_block_map_, - &program_->parameter_blocks_); + parameter_block_sizes[i]); } - // Check that the block sizes match the block sizes expected by the - // cost_function. - for (int i = 0; i < parameter_block_ptrs.size(); ++i) { - CHECK_EQ(cost_function->parameter_block_sizes()[i], - parameter_block_ptrs[i]->Size()) - << "The cost function expects parameter block " << i - << " of size " << cost_function->parameter_block_sizes()[i] - << " but was given a block of size " - << parameter_block_ptrs[i]->Size(); + if (!options_.disable_all_safety_checks) { + // Check that the block sizes match the block sizes expected by the + // cost_function. + for (int i = 0; i < parameter_block_ptrs.size(); ++i) { + CHECK_EQ(cost_function->parameter_block_sizes()[i], + parameter_block_ptrs[i]->Size()) + << "The cost function expects parameter block " << i + << " of size " << cost_function->parameter_block_sizes()[i] + << " but was given a block of size " + << parameter_block_ptrs[i]->Size(); + } } ResidualBlock* new_residual_block = new ResidualBlock(cost_function, loss_function, - parameter_block_ptrs); + parameter_block_ptrs, + program_->residual_blocks_.size()); + + // Add dependencies on the residual to the parameter blocks. + if (options_.enable_fast_parameter_block_removal) { + for (int i = 0; i < parameter_blocks.size(); ++i) { + parameter_block_ptrs[i]->AddResidualBlock(new_residual_block); + } + } + program_->residual_blocks_.push_back(new_residual_block); return new_residual_block; } // Unfortunately, macros don't help much to reduce this code, and var args don't // work because of the ambiguous case that there is no loss function. -const ResidualBlock* ProblemImpl::AddResidualBlock( +ResidualBlock* ProblemImpl::AddResidualBlock( CostFunction* cost_function, LossFunction* loss_function, double* x0) { @@ -241,7 +286,7 @@ const ResidualBlock* ProblemImpl::AddResidualBlock( return AddResidualBlock(cost_function, loss_function, residual_parameters); } -const ResidualBlock* ProblemImpl::AddResidualBlock( +ResidualBlock* ProblemImpl::AddResidualBlock( CostFunction* cost_function, LossFunction* loss_function, double* x0, double* x1) { @@ -251,7 +296,7 @@ const ResidualBlock* ProblemImpl::AddResidualBlock( return AddResidualBlock(cost_function, loss_function, residual_parameters); } -const ResidualBlock* ProblemImpl::AddResidualBlock( +ResidualBlock* ProblemImpl::AddResidualBlock( CostFunction* cost_function, LossFunction* loss_function, double* x0, double* x1, double* x2) { @@ -262,7 +307,7 @@ const ResidualBlock* ProblemImpl::AddResidualBlock( return AddResidualBlock(cost_function, loss_function, residual_parameters); } -const ResidualBlock* ProblemImpl::AddResidualBlock( +ResidualBlock* ProblemImpl::AddResidualBlock( CostFunction* cost_function, LossFunction* loss_function, double* x0, double* x1, double* x2, double* x3) { @@ -274,7 +319,7 @@ const ResidualBlock* ProblemImpl::AddResidualBlock( return AddResidualBlock(cost_function, loss_function, residual_parameters); } -const ResidualBlock* ProblemImpl::AddResidualBlock( +ResidualBlock* ProblemImpl::AddResidualBlock( CostFunction* cost_function, LossFunction* loss_function, double* x0, double* x1, double* x2, double* x3, double* x4) { @@ -287,7 +332,7 @@ const ResidualBlock* ProblemImpl::AddResidualBlock( return AddResidualBlock(cost_function, loss_function, residual_parameters); } -const ResidualBlock* ProblemImpl::AddResidualBlock( +ResidualBlock* ProblemImpl::AddResidualBlock( CostFunction* cost_function, LossFunction* loss_function, double* x0, double* x1, double* x2, double* x3, double* x4, double* x5) { @@ -301,12 +346,78 @@ const ResidualBlock* ProblemImpl::AddResidualBlock( return AddResidualBlock(cost_function, loss_function, residual_parameters); } +ResidualBlock* ProblemImpl::AddResidualBlock( + CostFunction* cost_function, + LossFunction* loss_function, + double* x0, double* x1, double* x2, double* x3, double* x4, double* x5, + double* x6) { + vector residual_parameters; + residual_parameters.push_back(x0); + residual_parameters.push_back(x1); + residual_parameters.push_back(x2); + residual_parameters.push_back(x3); + residual_parameters.push_back(x4); + residual_parameters.push_back(x5); + residual_parameters.push_back(x6); + return AddResidualBlock(cost_function, loss_function, residual_parameters); +} + +ResidualBlock* ProblemImpl::AddResidualBlock( + CostFunction* cost_function, + LossFunction* loss_function, + double* x0, double* x1, double* x2, double* x3, double* x4, double* x5, + double* x6, double* x7) { + vector residual_parameters; + residual_parameters.push_back(x0); + residual_parameters.push_back(x1); + residual_parameters.push_back(x2); + residual_parameters.push_back(x3); + residual_parameters.push_back(x4); + residual_parameters.push_back(x5); + residual_parameters.push_back(x6); + residual_parameters.push_back(x7); + return AddResidualBlock(cost_function, loss_function, residual_parameters); +} + +ResidualBlock* ProblemImpl::AddResidualBlock( + CostFunction* cost_function, + LossFunction* loss_function, + double* x0, double* x1, double* x2, double* x3, double* x4, double* x5, + double* x6, double* x7, double* x8) { + vector residual_parameters; + residual_parameters.push_back(x0); + residual_parameters.push_back(x1); + residual_parameters.push_back(x2); + residual_parameters.push_back(x3); + residual_parameters.push_back(x4); + residual_parameters.push_back(x5); + residual_parameters.push_back(x6); + residual_parameters.push_back(x7); + residual_parameters.push_back(x8); + return AddResidualBlock(cost_function, loss_function, residual_parameters); +} + +ResidualBlock* ProblemImpl::AddResidualBlock( + CostFunction* cost_function, + LossFunction* loss_function, + double* x0, double* x1, double* x2, double* x3, double* x4, double* x5, + double* x6, double* x7, double* x8, double* x9) { + vector residual_parameters; + residual_parameters.push_back(x0); + residual_parameters.push_back(x1); + residual_parameters.push_back(x2); + residual_parameters.push_back(x3); + residual_parameters.push_back(x4); + residual_parameters.push_back(x5); + residual_parameters.push_back(x6); + residual_parameters.push_back(x7); + residual_parameters.push_back(x8); + residual_parameters.push_back(x9); + return AddResidualBlock(cost_function, loss_function, residual_parameters); +} void ProblemImpl::AddParameterBlock(double* values, int size) { - InternalAddParameterBlock(values, - size, - ¶meter_block_map_, - &program_->parameter_blocks_); + InternalAddParameterBlock(values, size); } void ProblemImpl::AddParameterBlock( @@ -314,15 +425,83 @@ void ProblemImpl::AddParameterBlock( int size, LocalParameterization* local_parameterization) { ParameterBlock* parameter_block = - InternalAddParameterBlock(values, - size, - ¶meter_block_map_, - &program_->parameter_blocks_); + InternalAddParameterBlock(values, size); if (local_parameterization != NULL) { parameter_block->SetParameterization(local_parameterization); } } +// Delete a block from a vector of blocks, maintaining the indexing invariant. +// This is done in constant time by moving an element from the end of the +// vector over the element to remove, then popping the last element. It +// destroys the ordering in the interest of speed. +template +void ProblemImpl::DeleteBlockInVector(vector* mutable_blocks, + Block* block_to_remove) { + CHECK_EQ((*mutable_blocks)[block_to_remove->index()], block_to_remove) + << "You found a Ceres bug! Block: " << block_to_remove->ToString(); + + // Prepare the to-be-moved block for the new, lower-in-index position by + // setting the index to the blocks final location. + Block* tmp = mutable_blocks->back(); + tmp->set_index(block_to_remove->index()); + + // Overwrite the to-be-deleted residual block with the one at the end. + (*mutable_blocks)[block_to_remove->index()] = tmp; + + DeleteBlock(block_to_remove); + + // The block is gone so shrink the vector of blocks accordingly. + mutable_blocks->pop_back(); +} + +void ProblemImpl::RemoveResidualBlock(ResidualBlock* residual_block) { + CHECK_NOTNULL(residual_block); + + // If needed, remove the parameter dependencies on this residual block. + if (options_.enable_fast_parameter_block_removal) { + const int num_parameter_blocks_for_residual = + residual_block->NumParameterBlocks(); + for (int i = 0; i < num_parameter_blocks_for_residual; ++i) { + residual_block->parameter_blocks()[i] + ->RemoveResidualBlock(residual_block); + } + } + DeleteBlockInVector(program_->mutable_residual_blocks(), residual_block); +} + +void ProblemImpl::RemoveParameterBlock(double* values) { + ParameterBlock* parameter_block = FindOrDie(parameter_block_map_, values); + + if (options_.enable_fast_parameter_block_removal) { + // Copy the dependent residuals from the parameter block because the set of + // dependents will change after each call to RemoveResidualBlock(). + vector residual_blocks_to_remove( + parameter_block->mutable_residual_blocks()->begin(), + parameter_block->mutable_residual_blocks()->end()); + for (int i = 0; i < residual_blocks_to_remove.size(); ++i) { + RemoveResidualBlock(residual_blocks_to_remove[i]); + } + } else { + // Scan all the residual blocks to remove ones that depend on the parameter + // block. Do the scan backwards since the vector changes while iterating. + const int num_residual_blocks = NumResidualBlocks(); + for (int i = num_residual_blocks - 1; i >= 0; --i) { + ResidualBlock* residual_block = + (*(program_->mutable_residual_blocks()))[i]; + const int num_parameter_blocks = residual_block->NumParameterBlocks(); + for (int j = 0; j < num_parameter_blocks; ++j) { + if (residual_block->parameter_blocks()[j] == parameter_block) { + RemoveResidualBlock(residual_block); + // The parameter blocks are guaranteed unique. + break; + } + } + } + } + DeleteBlockInVector(program_->mutable_parameter_blocks(), parameter_block); +} + void ProblemImpl::SetParameterBlockConstant(double* values) { FindOrDie(parameter_block_map_, values)->SetConstant(); } @@ -338,6 +517,164 @@ void ProblemImpl::SetParameterization( ->SetParameterization(local_parameterization); } +bool ProblemImpl::Evaluate(const Problem::EvaluateOptions& evaluate_options, + double* cost, + vector* residuals, + vector* gradient, + CRSMatrix* jacobian) { + if (cost == NULL && + residuals == NULL && + gradient == NULL && + jacobian == NULL) { + LOG(INFO) << "Nothing to do."; + return true; + } + + // If the user supplied residual blocks, then use them, otherwise + // take the residual blocks from the underlying program. + Program program; + *program.mutable_residual_blocks() = + ((evaluate_options.residual_blocks.size() > 0) + ? evaluate_options.residual_blocks : program_->residual_blocks()); + + const vector& parameter_block_ptrs = + evaluate_options.parameter_blocks; + + vector variable_parameter_blocks; + vector& parameter_blocks = + *program.mutable_parameter_blocks(); + + if (parameter_block_ptrs.size() == 0) { + // The user did not provide any parameter blocks, so default to + // using all the parameter blocks in the order that they are in + // the underlying program object. + parameter_blocks = program_->parameter_blocks(); + } else { + // The user supplied a vector of parameter blocks. Using this list + // requires a number of steps. + + // 1. Convert double* into ParameterBlock* + parameter_blocks.resize(parameter_block_ptrs.size()); + for (int i = 0; i < parameter_block_ptrs.size(); ++i) { + parameter_blocks[i] = + FindOrDie(parameter_block_map_, parameter_block_ptrs[i]); + } + + // 2. The user may have only supplied a subset of parameter + // blocks, so identify the ones that are not supplied by the user + // and are NOT constant. These parameter blocks are stored in + // variable_parameter_blocks. + // + // To ensure that the parameter blocks are not included in the + // columns of the jacobian, we need to make sure that they are + // constant during evaluation and then make them variable again + // after we are done. + vector all_parameter_blocks(program_->parameter_blocks()); + vector included_parameter_blocks( + program.parameter_blocks()); + + vector excluded_parameter_blocks; + sort(all_parameter_blocks.begin(), all_parameter_blocks.end()); + sort(included_parameter_blocks.begin(), included_parameter_blocks.end()); + set_difference(all_parameter_blocks.begin(), + all_parameter_blocks.end(), + included_parameter_blocks.begin(), + included_parameter_blocks.end(), + back_inserter(excluded_parameter_blocks)); + + variable_parameter_blocks.reserve(excluded_parameter_blocks.size()); + for (int i = 0; i < excluded_parameter_blocks.size(); ++i) { + ParameterBlock* parameter_block = excluded_parameter_blocks[i]; + if (!parameter_block->IsConstant()) { + variable_parameter_blocks.push_back(parameter_block); + parameter_block->SetConstant(); + } + } + } + + // Setup the Parameter indices and offsets before an evaluator can + // be constructed and used. + program.SetParameterOffsetsAndIndex(); + + Evaluator::Options evaluator_options; + + // Even though using SPARSE_NORMAL_CHOLESKY requires SuiteSparse or + // CXSparse, here it just being used for telling the evaluator to + // use a SparseRowCompressedMatrix for the jacobian. This is because + // the Evaluator decides the storage for the Jacobian based on the + // type of linear solver being used. + evaluator_options.linear_solver_type = SPARSE_NORMAL_CHOLESKY; + evaluator_options.num_threads = evaluate_options.num_threads; + + string error; + scoped_ptr evaluator( + Evaluator::Create(evaluator_options, &program, &error)); + if (evaluator.get() == NULL) { + LOG(ERROR) << "Unable to create an Evaluator object. " + << "Error: " << error + << "This is a Ceres bug; please contact the developers!"; + + // Make the parameter blocks that were temporarily marked + // constant, variable again. + for (int i = 0; i < variable_parameter_blocks.size(); ++i) { + variable_parameter_blocks[i]->SetVarying(); + } + return false; + } + + if (residuals !=NULL) { + residuals->resize(evaluator->NumResiduals()); + } + + if (gradient != NULL) { + gradient->resize(evaluator->NumEffectiveParameters()); + } + + scoped_ptr tmp_jacobian; + if (jacobian != NULL) { + tmp_jacobian.reset( + down_cast(evaluator->CreateJacobian())); + } + + // Point the state pointers to the user state pointers. This is + // needed so that we can extract a parameter vector which is then + // passed to Evaluator::Evaluate. + program.SetParameterBlockStatePtrsToUserStatePtrs(); + + // Copy the value of the parameter blocks into a vector, since the + // Evaluate::Evaluate method needs its input as such. The previous + // call to SetParameterBlockStatePtrsToUserStatePtrs ensures that + // these values are the ones corresponding to the actual state of + // the parameter blocks, rather than the temporary state pointer + // used for evaluation. + Vector parameters(program.NumParameters()); + program.ParameterBlocksToStateVector(parameters.data()); + + double tmp_cost = 0; + bool status = evaluator->Evaluate(parameters.data(), + &tmp_cost, + residuals != NULL ? &(*residuals)[0] : NULL, + gradient != NULL ? &(*gradient)[0] : NULL, + tmp_jacobian.get()); + + // Make the parameter blocks that were temporarirly marked + // constant, variable again. + for (int i = 0; i < variable_parameter_blocks.size(); ++i) { + variable_parameter_blocks[i]->SetVarying(); + } + + if (status) { + if (cost != NULL) { + *cost = tmp_cost; + } + if (jacobian != NULL) { + tmp_jacobian->ToCRSMatrix(jacobian); + } + } + + return status; +} + int ProblemImpl::NumParameterBlocks() const { return program_->NumParameterBlocks(); } diff --git a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h index 2ca055448c3..ccc315de6b6 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h +++ b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h @@ -53,6 +53,7 @@ namespace ceres { class CostFunction; class LossFunction; class LocalParameterization; +struct CRSMatrix; namespace internal { @@ -93,14 +94,46 @@ class ProblemImpl { LossFunction* loss_function, double* x0, double* x1, double* x2, double* x3, double* x4, double* x5); + ResidualBlockId AddResidualBlock(CostFunction* cost_function, + LossFunction* loss_function, + double* x0, double* x1, double* x2, + double* x3, double* x4, double* x5, + double* x6); + ResidualBlockId AddResidualBlock(CostFunction* cost_function, + LossFunction* loss_function, + double* x0, double* x1, double* x2, + double* x3, double* x4, double* x5, + double* x6, double* x7); + ResidualBlockId AddResidualBlock(CostFunction* cost_function, + LossFunction* loss_function, + double* x0, double* x1, double* x2, + double* x3, double* x4, double* x5, + double* x6, double* x7, double* x8); + ResidualBlockId AddResidualBlock(CostFunction* cost_function, + LossFunction* loss_function, + double* x0, double* x1, double* x2, + double* x3, double* x4, double* x5, + double* x6, double* x7, double* x8, + double* x9); void AddParameterBlock(double* values, int size); void AddParameterBlock(double* values, int size, LocalParameterization* local_parameterization); + + void RemoveResidualBlock(ResidualBlock* residual_block); + void RemoveParameterBlock(double* values); + void SetParameterBlockConstant(double* values); void SetParameterBlockVariable(double* values); void SetParameterization(double* values, LocalParameterization* local_parameterization); + + bool Evaluate(const Problem::EvaluateOptions& options, + double* cost, + vector* residuals, + vector* gradient, + CRSMatrix* jacobian); + int NumParameterBlocks() const; int NumParameters() const; int NumResidualBlocks() const; @@ -112,12 +145,41 @@ class ProblemImpl { const ParameterMap& parameter_map() const { return parameter_block_map_; } private: + ParameterBlock* InternalAddParameterBlock(double* values, int size); + + bool InternalEvaluate(Program* program, + double* cost, + vector* residuals, + vector* gradient, + CRSMatrix* jacobian); + + // Delete the arguments in question. These differ from the Remove* functions + // in that they do not clean up references to the block to delete; they + // merely delete them. + template + void DeleteBlockInVector(vector* mutable_blocks, + Block* block_to_remove); + void DeleteBlock(ResidualBlock* residual_block); + void DeleteBlock(ParameterBlock* parameter_block); + const Problem::Options options_; // The mapping from user pointers to parameter blocks. map parameter_block_map_; + // The actual parameter and residual blocks. internal::scoped_ptr program_; + + // When removing residual and parameter blocks, cost/loss functions and + // parameterizations have ambiguous ownership. Instead of scanning the entire + // problem to see if the cost/loss/parameterization is shared with other + // residual or parameter blocks, buffer them until destruction. + // + // TODO(keir): See if it makes sense to use sets instead. + vector cost_functions_to_delete_; + vector loss_functions_to_delete_; + vector local_parameterizations_to_delete_; + CERES_DISALLOW_COPY_AND_ASSIGN(ProblemImpl); }; diff --git a/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h b/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h index 6c48e7d7643..a19cdf8a86a 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h +++ b/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h @@ -83,11 +83,14 @@ #include #endif +#include +#include +#include "ceres/execution_summary.h" +#include "ceres/internal/eigen.h" +#include "ceres/internal/scoped_ptr.h" #include "ceres/parameter_block.h" #include "ceres/program.h" #include "ceres/residual_block.h" -#include "ceres/internal/eigen.h" -#include "ceres/internal/scoped_ptr.h" namespace ceres { namespace internal { @@ -122,6 +125,12 @@ class ProgramEvaluator : public Evaluator { double* residuals, double* gradient, SparseMatrix* jacobian) { + ScopedExecutionTimer total_timer("Evaluator::Total", &execution_summary_); + ScopedExecutionTimer call_type_timer(gradient == NULL && jacobian == NULL + ? "Evaluator::Residual" + : "Evaluator::Jacobian", + &execution_summary_); + // The parameters are stateful, so set the state before evaluating. if (!program_->StateVectorToParameterBlocks(state)) { return false; @@ -129,7 +138,7 @@ class ProgramEvaluator : public Evaluator { if (residuals != NULL) { VectorRef(residuals, program_->NumResiduals()).setZero(); - } + } if (jacobian != NULL) { jacobian->SetZero(); @@ -138,6 +147,10 @@ class ProgramEvaluator : public Evaluator { // Each thread gets it's own cost and evaluate scratch space. for (int i = 0; i < options_.num_threads; ++i) { evaluate_scratch_[i].cost = 0.0; + if (gradient != NULL) { + VectorRef(evaluate_scratch_[i].gradient.get(), + program_->NumEffectiveParameters()).setZero(); + } } // This bool is used to disable the loop if an error is encountered @@ -262,6 +275,14 @@ class ProgramEvaluator : public Evaluator { return program_->NumResiduals(); } + virtual map CallStatistics() const { + return execution_summary_.calls(); + } + + virtual map TimeStatistics() const { + return execution_summary_.times(); + } + private: // Per-thread scratch space needed to evaluate and store each residual block. struct EvaluateScratch { @@ -327,6 +348,7 @@ class ProgramEvaluator : public Evaluator { scoped_array evaluate_preparers_; scoped_array evaluate_scratch_; vector residual_layout_; + ::ceres::internal::ExecutionSummary execution_summary_; }; } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc b/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc index bdb88b1dd97..7f789605e5f 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc @@ -49,12 +49,14 @@ namespace internal { ResidualBlock::ResidualBlock(const CostFunction* cost_function, const LossFunction* loss_function, - const vector& parameter_blocks) + const vector& parameter_blocks, + int index) : cost_function_(cost_function), loss_function_(loss_function), parameter_blocks_( new ParameterBlock* [ - cost_function->parameter_block_sizes().size()]) { + cost_function->parameter_block_sizes().size()]), + index_(index) { std::copy(parameter_blocks.begin(), parameter_blocks.end(), parameter_blocks_.get()); diff --git a/extern/libmv/third_party/ceres/internal/ceres/residual_block.h b/extern/libmv/third_party/ceres/internal/ceres/residual_block.h index e0a06e78958..3921d1d4678 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/residual_block.h +++ b/extern/libmv/third_party/ceres/internal/ceres/residual_block.h @@ -34,11 +34,13 @@ #ifndef CERES_INTERNAL_RESIDUAL_BLOCK_H_ #define CERES_INTERNAL_RESIDUAL_BLOCK_H_ +#include #include #include "ceres/cost_function.h" #include "ceres/internal/port.h" #include "ceres/internal/scoped_ptr.h" +#include "ceres/stringprintf.h" #include "ceres/types.h" namespace ceres { @@ -64,9 +66,13 @@ class ParameterBlock; // loss functions, and parameter blocks. class ResidualBlock { public: + // Construct the residual block with the given cost/loss functions. Loss may + // be null. The index is the index of the residual block in the Program's + // residual_blocks array. ResidualBlock(const CostFunction* cost_function, const LossFunction* loss_function, - const vector& parameter_blocks); + const vector& parameter_blocks, + int index); // Evaluates the residual term, storing the scalar cost in *cost, the residual // components in *residuals, and the jacobians between the parameters and @@ -112,10 +118,23 @@ class ResidualBlock { // The minimum amount of scratch space needed to pass to Evaluate(). int NumScratchDoublesForEvaluate() const; + // This residual block's index in an array. + int index() const { return index_; } + void set_index(int index) { index_ = index; } + + string ToString() { + return StringPrintf("{residual block; index=%d}", index_); + } + private: const CostFunction* cost_function_; const LossFunction* loss_function_; scoped_array parameter_blocks_; + + // The index of the residual, typically in a Program. This is only to permit + // switching from a ResidualBlock* to an index in the Program's array, needed + // to do efficient removals. + int32 index_; }; } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc b/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc index 9442bb2a1c1..4d88a9f4f8a 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc @@ -63,7 +63,8 @@ void InvalidateEvaluation(const ResidualBlock& block, // Utility routine to print an array of doubles to a string. If the // array pointer is NULL, it is treated as an array of zeros. -static void AppendArrayToString(const int size, const double* x, string* result) { +namespace { +void AppendArrayToString(const int size, const double* x, string* result) { for (int i = 0; i < size; ++i) { if (x == NULL) { StringAppendF(result, "Not Computed "); @@ -76,6 +77,7 @@ static void AppendArrayToString(const int size, const double* x, string* result) } } } +} // namespace string EvaluationToString(const ResidualBlock& block, double const* const* parameters, diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc index 2cbe78d133a..17537596c75 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc @@ -38,22 +38,21 @@ #endif // CERES_NO_CXSPARSE #include "Eigen/Dense" -#include "glog/logging.h" #include "ceres/block_random_access_dense_matrix.h" #include "ceres/block_random_access_matrix.h" #include "ceres/block_random_access_sparse_matrix.h" #include "ceres/block_sparse_matrix.h" #include "ceres/block_structure.h" #include "ceres/detect_structure.h" +#include "ceres/internal/eigen.h" +#include "ceres/internal/port.h" +#include "ceres/internal/scoped_ptr.h" #include "ceres/linear_solver.h" #include "ceres/schur_complement_solver.h" #include "ceres/suitesparse.h" #include "ceres/triplet_sparse_matrix.h" -#include "ceres/internal/eigen.h" -#include "ceres/internal/port.h" -#include "ceres/internal/scoped_ptr.h" #include "ceres/types.h" - +#include "ceres/wall_time.h" namespace ceres { namespace internal { @@ -63,43 +62,39 @@ LinearSolver::Summary SchurComplementSolver::SolveImpl( const double* b, const LinearSolver::PerSolveOptions& per_solve_options, double* x) { - const time_t start_time = time(NULL); + EventLogger event_logger("SchurComplementSolver::Solve"); + if (eliminator_.get() == NULL) { InitStorage(A->block_structure()); DetectStructure(*A->block_structure(), - options_.num_eliminate_blocks, + options_.elimination_groups[0], &options_.row_block_size, &options_.e_block_size, &options_.f_block_size); eliminator_.reset(CHECK_NOTNULL(SchurEliminatorBase::Create(options_))); - eliminator_->Init(options_.num_eliminate_blocks, A->block_structure()); + eliminator_->Init(options_.elimination_groups[0], A->block_structure()); }; - const time_t init_time = time(NULL); fill(x, x + A->num_cols(), 0.0); + event_logger.AddEvent("Setup"); LinearSolver::Summary summary; summary.num_iterations = 1; summary.termination_type = FAILURE; eliminator_->Eliminate(A, b, per_solve_options.D, lhs_.get(), rhs_.get()); - const time_t eliminate_time = time(NULL); + event_logger.AddEvent("Eliminate"); double* reduced_solution = x + A->num_cols() - lhs_->num_cols(); const bool status = SolveReducedLinearSystem(reduced_solution); - const time_t solve_time = time(NULL); + event_logger.AddEvent("ReducedSolve"); if (!status) { return summary; } eliminator_->BackSubstitute(A, b, per_solve_options.D, reduced_solution, x); - const time_t backsubstitute_time = time(NULL); summary.termination_type = TOLERANCE; - VLOG(2) << "time (sec) total: " << (backsubstitute_time - start_time) - << " init: " << (init_time - start_time) - << " eliminate: " << (eliminate_time - init_time) - << " solve: " << (solve_time - eliminate_time) - << " backsubstitute: " << (backsubstitute_time - solve_time); + event_logger.AddEvent("BackSubstitute"); return summary; } @@ -107,7 +102,7 @@ LinearSolver::Summary SchurComplementSolver::SolveImpl( // complement. void DenseSchurComplementSolver::InitStorage( const CompressedRowBlockStructure* bs) { - const int num_eliminate_blocks = options().num_eliminate_blocks; + const int num_eliminate_blocks = options().elimination_groups[0]; const int num_col_blocks = bs->cols.size(); vector blocks(num_col_blocks - num_eliminate_blocks, 0); @@ -179,7 +174,7 @@ SparseSchurComplementSolver::~SparseSchurComplementSolver() { // initialize a BlockRandomAccessSparseMatrix object. void SparseSchurComplementSolver::InitStorage( const CompressedRowBlockStructure* bs) { - const int num_eliminate_blocks = options().num_eliminate_blocks; + const int num_eliminate_blocks = options().elimination_groups[0]; const int num_col_blocks = bs->cols.size(); const int num_row_blocks = bs->rows.size(); @@ -268,8 +263,6 @@ bool SparseSchurComplementSolver::SolveReducedLinearSystem(double* solution) { // CHOLMOD's sparse cholesky factorization routines. bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse( double* solution) { - const time_t start_time = time(NULL); - TripletSparseMatrix* tsm = const_cast( down_cast(lhs())->matrix()); @@ -286,11 +279,9 @@ bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse( // The matrix is symmetric, and the upper triangular part of the // matrix contains the values. cholmod_lhs->stype = 1; - const time_t lhs_time = time(NULL); cholmod_dense* cholmod_rhs = ss_.CreateDenseVector(const_cast(rhs()), num_rows, num_rows); - const time_t rhs_time = time(NULL); // Symbolic factorization is computed if we don't already have one handy. if (factor_ == NULL) { @@ -307,32 +298,22 @@ bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse( CHECK_NOTNULL(factor_); - const time_t symbolic_time = time(NULL); cholmod_dense* cholmod_solution = ss_.SolveCholesky(cholmod_lhs, factor_, cholmod_rhs); - const time_t solve_time = time(NULL); - ss_.Free(cholmod_lhs); cholmod_lhs = NULL; ss_.Free(cholmod_rhs); cholmod_rhs = NULL; if (cholmod_solution == NULL) { - LOG(ERROR) << "CHOLMOD solve failed."; + LOG(WARNING) << "CHOLMOD solve failed."; return false; } VectorRef(solution, num_rows) = VectorRef(static_cast(cholmod_solution->x), num_rows); ss_.Free(cholmod_solution); - const time_t final_time = time(NULL); - VLOG(2) << "time: " << (final_time - start_time) - << " lhs : " << (lhs_time - start_time) - << " rhs: " << (rhs_time - lhs_time) - << " analyze: " << (symbolic_time - rhs_time) - << " factor_and_solve: " << (solve_time - symbolic_time) - << " cleanup: " << (final_time - solve_time); return true; } #else diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h b/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h index ea1b3184c33..7e98f316255 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h +++ b/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h @@ -33,6 +33,7 @@ #include #include +#include #include "ceres/block_random_access_matrix.h" #include "ceres/block_sparse_matrix.h" @@ -97,13 +98,14 @@ class BlockSparseMatrixBase; // The two solvers can be instantiated by calling // LinearSolver::CreateLinearSolver with LinearSolver::Options::type // set to DENSE_SCHUR and SPARSE_SCHUR -// respectively. LinearSolver::Options::num_eliminate_blocks should be +// respectively. LinearSolver::Options::elimination_groups[0] should be // at least 1. class SchurComplementSolver : public BlockSparseMatrixBaseSolver { public: explicit SchurComplementSolver(const LinearSolver::Options& options) : options_(options) { - CHECK_GT(options.num_eliminate_blocks, 0); + CHECK_GT(options.elimination_groups.size(), 1); + CHECK_GT(options.elimination_groups[0], 0); } // LinearSolver methods diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h b/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h index 6120db9b009..339c44bc41c 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h +++ b/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h @@ -50,7 +50,6 @@ #include #include -#include #include "Eigen/Dense" #include "ceres/block_random_access_matrix.h" #include "ceres/block_sparse_matrix.h" @@ -60,6 +59,7 @@ #include "ceres/stl_util.h" #include "ceres/internal/eigen.h" #include "ceres/internal/scoped_ptr.h" +#include "glog/logging.h" namespace ceres { namespace internal { diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc b/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc new file mode 100644 index 00000000000..33a666ed037 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc @@ -0,0 +1,145 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2013 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#include "ceres/schur_jacobi_preconditioner.h" + +#include +#include +#include "Eigen/Dense" +#include "ceres/block_random_access_sparse_matrix.h" +#include "ceres/block_sparse_matrix.h" +#include "ceres/collections_port.h" +#include "ceres/detect_structure.h" +#include "ceres/internal/scoped_ptr.h" +#include "ceres/linear_solver.h" +#include "ceres/schur_eliminator.h" +#include "glog/logging.h" + +namespace ceres { +namespace internal { + +SchurJacobiPreconditioner::SchurJacobiPreconditioner( + const CompressedRowBlockStructure& bs, + const Preconditioner::Options& options) + : options_(options) { + CHECK_GT(options_.elimination_groups.size(), 1); + CHECK_GT(options_.elimination_groups[0], 0); + const int num_blocks = bs.cols.size() - options_.elimination_groups[0]; + CHECK_GT(num_blocks, 0) + << "Jacobian should have atleast 1 f_block for " + << "SCHUR_JACOBI preconditioner."; + + block_size_.resize(num_blocks); + set > block_pairs; + + int num_block_diagonal_entries = 0; + for (int i = 0; i < num_blocks; ++i) { + block_size_[i] = bs.cols[i + options_.elimination_groups[0]].size; + block_pairs.insert(make_pair(i, i)); + num_block_diagonal_entries += block_size_[i] * block_size_[i]; + } + + m_.reset(new BlockRandomAccessSparseMatrix(block_size_, block_pairs)); + InitEliminator(bs); +} + +SchurJacobiPreconditioner::~SchurJacobiPreconditioner() { +} + +// Initialize the SchurEliminator. +void SchurJacobiPreconditioner::InitEliminator( + const CompressedRowBlockStructure& bs) { + LinearSolver::Options eliminator_options; + + eliminator_options.elimination_groups = options_.elimination_groups; + eliminator_options.num_threads = options_.num_threads; + + DetectStructure(bs, options_.elimination_groups[0], + &eliminator_options.row_block_size, + &eliminator_options.e_block_size, + &eliminator_options.f_block_size); + + eliminator_.reset(SchurEliminatorBase::Create(eliminator_options)); + eliminator_->Init(options_.elimination_groups[0], &bs); +} + +// Update the values of the preconditioner matrix and factorize it. +bool SchurJacobiPreconditioner::Update(const BlockSparseMatrixBase& A, + const double* D) { + const int num_rows = m_->num_rows(); + CHECK_GT(num_rows, 0); + + // We need a dummy rhs vector and a dummy b vector since the Schur + // eliminator combines the computation of the reduced camera matrix + // with the computation of the right hand side of that linear + // system. + // + // TODO(sameeragarwal): Perhaps its worth refactoring the + // SchurEliminator::Eliminate function to allow NULL for the rhs. As + // of now it does not seem to be worth the effort. + Vector rhs = Vector::Zero(m_->num_rows()); + Vector b = Vector::Zero(A.num_rows()); + + // Compute a subset of the entries of the Schur complement. + eliminator_->Eliminate(&A, b.data(), D, m_.get(), rhs.data()); + return true; +} + +void SchurJacobiPreconditioner::RightMultiply(const double* x, + double* y) const { + CHECK_NOTNULL(x); + CHECK_NOTNULL(y); + + const double* lhs_values = + down_cast(m_.get())->matrix()->values(); + + // This loop can be easily multi-threaded with OpenMP if need be. + for (int i = 0; i < block_size_.size(); ++i) { + const int block_size = block_size_[i]; + ConstMatrixRef block(lhs_values, block_size, block_size); + + VectorRef(y, block_size) = + block + .selfadjointView() + .ldlt() + .solve(ConstVectorRef(x, block_size)); + + x += block_size; + y += block_size; + lhs_values += block_size * block_size; + } +} + +int SchurJacobiPreconditioner::num_rows() const { + return m_->num_rows(); +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h b/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h new file mode 100644 index 00000000000..3addd73abd2 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h @@ -0,0 +1,110 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2013 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) +// +// Detailed descriptions of these preconditions beyond what is +// documented here can be found in +// +// Bundle Adjustment in the Large +// S. Agarwal, N. Snavely, S. Seitz & R. Szeliski, ECCV 2010 +// http://www.cs.washington.edu/homes/sagarwal/bal.pdf + +#ifndef CERES_INTERNAL_SCHUR_JACOBI_PRECONDITIONER_H_ +#define CERES_INTERNAL_SCHUR_JACOBI_PRECONDITIONER_H_ + +#include +#include +#include +#include "ceres/collections_port.h" +#include "ceres/internal/macros.h" +#include "ceres/internal/scoped_ptr.h" +#include "ceres/preconditioner.h" + +namespace ceres { +namespace internal { + +class BlockRandomAccessSparseMatrix; +class BlockSparseMatrixBase; +struct CompressedRowBlockStructure; +class SchurEliminatorBase; + +// This class implements the SCHUR_JACOBI preconditioner for Structure +// from Motion/Bundle Adjustment problems. Full mathematical details +// can be found in +// +// Bundle Adjustment in the Large +// S. Agarwal, N. Snavely, S. Seitz & R. Szeliski, ECCV 2010 +// http://www.cs.washington.edu/homes/sagarwal/bal.pdf +// +// Example usage: +// +// Preconditioner::Options options; +// options.preconditioner_type = SCHUR_JACOBI; +// options.elimination_groups.push_back(num_points); +// options.elimination_groups.push_back(num_cameras); +// SchurJacobiPreconditioner preconditioner( +// *A.block_structure(), options); +// preconditioner.Update(A, NULL); +// preconditioner.RightMultiply(x, y); +// +class SchurJacobiPreconditioner : public Preconditioner { + public: + // Initialize the symbolic structure of the preconditioner. bs is + // the block structure of the linear system to be solved. It is used + // to determine the sparsity structure of the preconditioner matrix. + // + // It has the same structural requirement as other Schur complement + // based solvers. Please see schur_eliminator.h for more details. + SchurJacobiPreconditioner(const CompressedRowBlockStructure& bs, + const Preconditioner::Options& options); + virtual ~SchurJacobiPreconditioner(); + + // Preconditioner interface. + virtual bool Update(const BlockSparseMatrixBase& A, const double* D); + virtual void RightMultiply(const double* x, double* y) const; + virtual int num_rows() const; + + private: + void InitEliminator(const CompressedRowBlockStructure& bs); + + Preconditioner::Options options_; + + // Sizes of the blocks in the schur complement. + vector block_size_; + scoped_ptr eliminator_; + + // Preconditioner matrix. + scoped_ptr m_; + CERES_DISALLOW_COPY_AND_ASSIGN(SchurJacobiPreconditioner); +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_SCHUR_JACOBI_PRECONDITIONER_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.cc b/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.cc deleted file mode 100644 index 1cdff4e6dec..00000000000 --- a/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.cc +++ /dev/null @@ -1,101 +0,0 @@ -// Ceres Solver - A fast non-linear least squares minimizer -// Copyright 2010, 2011, 2012 Google Inc. All rights reserved. -// http://code.google.com/p/ceres-solver/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of Google Inc. nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Author: sameeragarwal@google.com (Sameer Agarwal) - -#include "ceres/schur_ordering.h" - -#include "ceres/graph.h" -#include "ceres/graph_algorithms.h" -#include "ceres/internal/scoped_ptr.h" -#include "ceres/map_util.h" -#include "ceres/parameter_block.h" -#include "ceres/program.h" -#include "ceres/residual_block.h" -#include "glog/logging.h" - -namespace ceres { -namespace internal { - -int ComputeSchurOrdering(const Program& program, - vector* ordering) { - CHECK_NOTNULL(ordering)->clear(); - - scoped_ptr > graph( - CHECK_NOTNULL(CreateHessianGraph(program))); - int independent_set_size = IndependentSetOrdering(*graph, ordering); - const vector& parameter_blocks = program.parameter_blocks(); - - // Add the excluded blocks to back of the ordering vector. - for (int i = 0; i < parameter_blocks.size(); ++i) { - ParameterBlock* parameter_block = parameter_blocks[i]; - if (parameter_block->IsConstant()) { - ordering->push_back(parameter_block); - } - } - - return independent_set_size; -} - -Graph* -CreateHessianGraph(const Program& program) { - Graph* graph = new Graph; - const vector& parameter_blocks = program.parameter_blocks(); - for (int i = 0; i < parameter_blocks.size(); ++i) { - ParameterBlock* parameter_block = parameter_blocks[i]; - if (!parameter_block->IsConstant()) { - graph->AddVertex(parameter_block); - } - } - - const vector& residual_blocks = program.residual_blocks(); - for (int i = 0; i < residual_blocks.size(); ++i) { - const ResidualBlock* residual_block = residual_blocks[i]; - const int num_parameter_blocks = residual_block->NumParameterBlocks(); - ParameterBlock* const* parameter_blocks = - residual_block->parameter_blocks(); - for (int j = 0; j < num_parameter_blocks; ++j) { - if (parameter_blocks[j]->IsConstant()) { - continue; - } - - for (int k = j + 1; k < num_parameter_blocks; ++k) { - if (parameter_blocks[k]->IsConstant()) { - continue; - } - - graph->AddEdge(parameter_blocks[j], parameter_blocks[k]); - } - } - } - - return graph; -} - -} // namespace internal -} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.h b/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.h deleted file mode 100644 index 1f9a4ff354f..00000000000 --- a/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.h +++ /dev/null @@ -1,74 +0,0 @@ -// Ceres Solver - A fast non-linear least squares minimizer -// Copyright 2010, 2011, 2012 Google Inc. All rights reserved. -// http://code.google.com/p/ceres-solver/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of Google Inc. nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Author: sameeragarwal@google.com (Sameer Agarwal) -// -// Compute a parameter block ordering for use with the Schur -// complement based algorithms. - -#ifndef CERES_INTERNAL_SCHUR_ORDERING_H_ -#define CERES_INTERNAL_SCHUR_ORDERING_H_ - -#include -#include "ceres/graph.h" -#include "ceres/types.h" - -namespace ceres { -namespace internal { - -class Program; -class ParameterBlock; - -// Uses an approximate independent set ordering to order the parameter -// blocks of a problem so that it is suitable for use with Schur -// complement based solvers. The output variable ordering contains an -// ordering of the parameter blocks and the return value is size of -// the independent set or the number of e_blocks (see -// schur_complement_solver.h for an explanation). Constant parameters -// are added to the end. -// -// The ordering vector has the structure -// -// ordering = [independent set, -// complement of the independent set, -// fixed blocks] -int ComputeSchurOrdering(const Program& program, - vector* ordering); - - -// Builds a graph on the parameter blocks of a Problem, whose -// structure reflects the sparsity structure of the Hessian. Each -// vertex corresponds to a parameter block in the Problem except for -// parameter blocks that are marked constant. An edge connects two -// parameter blocks, if they co-occur in a residual block. -Graph* CreateHessianGraph(const Program& program); - -} // namespace internal -} // namespace ceres - -#endif // CERES_INTERNAL_SCHUR_ORDERING_H_ diff --git a/extern/libmv/third_party/ceres/internal/ceres/solver.cc b/extern/libmv/third_party/ceres/internal/ceres/solver.cc index 66ca93283a1..6436d2df2a7 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/solver.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/solver.cc @@ -37,20 +37,41 @@ #include "ceres/program.h" #include "ceres/solver_impl.h" #include "ceres/stringprintf.h" +#include "ceres/wall_time.h" namespace ceres { +namespace { + +void StringifyOrdering(const vector& ordering, string* report) { + if (ordering.size() == 0) { + internal::StringAppendF(report, "AUTOMATIC"); + return; + } + + for (int i = 0; i < ordering.size() - 1; ++i) { + internal::StringAppendF(report, "%d, ", ordering[i]); + } + internal::StringAppendF(report, "%d", ordering.back()); +} + +} // namespace + +Solver::Options::~Options() { + delete linear_solver_ordering; + delete inner_iteration_ordering; +} Solver::~Solver() {} -// TODO(sameeragarwal): Use subsecond timers. void Solver::Solve(const Solver::Options& options, Problem* problem, Solver::Summary* summary) { - time_t start_time_seconds = time(NULL); + double start_time_seconds = internal::WallTimeInSeconds(); internal::ProblemImpl* problem_impl = CHECK_NOTNULL(problem)->problem_impl_.get(); internal::SolverImpl::Solve(options, problem_impl, summary); - summary->total_time_in_seconds = time(NULL) - start_time_seconds; + summary->total_time_in_seconds = + internal::WallTimeInSeconds() - start_time_seconds; } void Solve(const Solver::Options& options, @@ -63,7 +84,8 @@ void Solve(const Solver::Options& options, Solver::Summary::Summary() // Invalid values for most fields, to ensure that we are not // accidentally reporting default values. - : termination_type(DID_NOT_RUN), + : minimizer_type(TRUST_REGION), + termination_type(DID_NOT_RUN), initial_cost(-1.0), final_cost(-1.0), fixed_cost(-1.0), @@ -73,6 +95,9 @@ Solver::Summary::Summary() minimizer_time_in_seconds(-1.0), postprocessor_time_in_seconds(-1.0), total_time_in_seconds(-1.0), + linear_solver_time_in_seconds(-1.0), + residual_evaluation_time_in_seconds(-1.0), + jacobian_evaluation_time_in_seconds(-1.0), num_parameter_blocks(-1), num_parameters(-1), num_residual_blocks(-1), @@ -81,8 +106,6 @@ Solver::Summary::Summary() num_parameters_reduced(-1), num_residual_blocks_reduced(-1), num_residuals_reduced(-1), - num_eliminate_blocks_given(-1), - num_eliminate_blocks_used(-1), num_threads_given(-1), num_threads_used(-1), num_linear_solver_threads_given(-1), @@ -90,9 +113,11 @@ Solver::Summary::Summary() linear_solver_type_given(SPARSE_NORMAL_CHOLESKY), linear_solver_type_used(SPARSE_NORMAL_CHOLESKY), preconditioner_type(IDENTITY), - ordering_type(NATURAL), trust_region_strategy_type(LEVENBERG_MARQUARDT), - sparse_linear_algebra_library(SUITE_SPARSE) { + inner_iterations(false), + sparse_linear_algebra_library(SUITE_SPARSE), + line_search_direction_type(LBFGS), + line_search_type(ARMIJO) { } string Solver::Summary::BriefReport() const { @@ -121,6 +146,8 @@ string Solver::Summary::BriefReport() const { return report; }; +using internal::StringAppendF; + string Solver::Summary::FullReport() const { string report = "\n" @@ -128,124 +155,210 @@ string Solver::Summary::FullReport() const { "-------------------\n"; if (termination_type == DID_NOT_RUN) { - internal::StringAppendF(&report, " Original\n"); - internal::StringAppendF(&report, "Parameter blocks % 10d\n", - num_parameter_blocks); - internal::StringAppendF(&report, "Parameters % 10d\n", - num_parameters); - internal::StringAppendF(&report, "Residual blocks % 10d\n", - num_residual_blocks); - internal::StringAppendF(&report, "Residuals % 10d\n\n", - num_residuals); + StringAppendF(&report, " Original\n"); + StringAppendF(&report, "Parameter blocks % 10d\n", + num_parameter_blocks); + StringAppendF(&report, "Parameters % 10d\n", + num_parameters); + StringAppendF(&report, "Residual blocks % 10d\n", + num_residual_blocks); + StringAppendF(&report, "Residuals % 10d\n\n", + num_residuals); } else { - internal::StringAppendF(&report, "%45s %21s\n", "Original", "Reduced"); - internal::StringAppendF(&report, "Parameter blocks % 25d% 25d\n", - num_parameter_blocks, num_parameter_blocks_reduced); - internal::StringAppendF(&report, "Parameters % 25d% 25d\n", - num_parameters, num_parameters_reduced); - internal::StringAppendF(&report, "Residual blocks % 25d% 25d\n", - num_residual_blocks, num_residual_blocks_reduced); - internal::StringAppendF(&report, "Residual % 25d% 25d\n\n", - num_residuals, num_residuals_reduced); + StringAppendF(&report, "%45s %21s\n", "Original", "Reduced"); + StringAppendF(&report, "Parameter blocks % 25d% 25d\n", + num_parameter_blocks, num_parameter_blocks_reduced); + StringAppendF(&report, "Parameters % 25d% 25d\n", + num_parameters, num_parameters_reduced); + StringAppendF(&report, "Residual blocks % 25d% 25d\n", + num_residual_blocks, num_residual_blocks_reduced); + StringAppendF(&report, "Residual % 25d% 25d\n", + num_residuals, num_residuals_reduced); } - internal::StringAppendF(&report, "%45s %21s\n", "Given", "Used"); - internal::StringAppendF(&report, "Linear solver %25s%25s\n", - LinearSolverTypeToString(linear_solver_type_given), - LinearSolverTypeToString(linear_solver_type_used)); + // TODO(sameeragarwal): Refactor this into separate functions. - if (linear_solver_type_given == CGNR || - linear_solver_type_given == ITERATIVE_SCHUR) { - internal::StringAppendF(&report, "Preconditioner %25s%25s\n", - PreconditionerTypeToString(preconditioner_type), - PreconditionerTypeToString(preconditioner_type)); - } else { - internal::StringAppendF(&report, "Preconditioner %25s%25s\n", - "N/A", "N/A"); - } + if (minimizer_type == TRUST_REGION) { + StringAppendF(&report, "\nMinimizer %19s\n", + "TRUST_REGION"); + if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY || + linear_solver_type_used == SPARSE_SCHUR || + (linear_solver_type_used == ITERATIVE_SCHUR && + (preconditioner_type == CLUSTER_JACOBI || + preconditioner_type == CLUSTER_TRIDIAGONAL))) { + StringAppendF(&report, "\nSparse Linear Algebra Library %15s\n", + SparseLinearAlgebraLibraryTypeToString( + sparse_linear_algebra_library)); + } - internal::StringAppendF(&report, "Ordering %25s%25s\n", - OrderingTypeToString(ordering_type), - OrderingTypeToString(ordering_type)); + StringAppendF(&report, "Trust Region Strategy %19s", + TrustRegionStrategyTypeToString( + trust_region_strategy_type)); + if (trust_region_strategy_type == DOGLEG) { + if (dogleg_type == TRADITIONAL_DOGLEG) { + StringAppendF(&report, " (TRADITIONAL)"); + } else { + StringAppendF(&report, " (SUBSPACE)"); + } + } + StringAppendF(&report, "\n"); + StringAppendF(&report, "\n"); + + StringAppendF(&report, "%45s %21s\n", "Given", "Used"); + StringAppendF(&report, "Linear solver %25s%25s\n", + LinearSolverTypeToString(linear_solver_type_given), + LinearSolverTypeToString(linear_solver_type_used)); - if (IsSchurType(linear_solver_type_given)) { - if (ordering_type == SCHUR) { - internal::StringAppendF(&report, "num_eliminate_blocks%25s% 25d\n", - "N/A", - num_eliminate_blocks_used); + if (linear_solver_type_given == CGNR || + linear_solver_type_given == ITERATIVE_SCHUR) { + StringAppendF(&report, "Preconditioner %25s%25s\n", + PreconditionerTypeToString(preconditioner_type), + PreconditionerTypeToString(preconditioner_type)); } else { - internal::StringAppendF(&report, "num_eliminate_blocks% 25d% 25d\n", - num_eliminate_blocks_given, - num_eliminate_blocks_used); + StringAppendF(&report, "Preconditioner %25s%25s\n", + "N/A", "N/A"); } - } - internal::StringAppendF(&report, "Threads: % 25d% 25d\n", - num_threads_given, num_threads_used); - internal::StringAppendF(&report, "Linear solver threads % 23d% 25d\n", - num_linear_solver_threads_given, - num_linear_solver_threads_used); - - if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY || - linear_solver_type_used == SPARSE_SCHUR || - (linear_solver_type_used == ITERATIVE_SCHUR && - (preconditioner_type == SCHUR_JACOBI || - preconditioner_type == CLUSTER_JACOBI || - preconditioner_type == CLUSTER_TRIDIAGONAL))) { - internal::StringAppendF(&report, "\nSparse Linear Algebra Library %15s\n", - SparseLinearAlgebraLibraryTypeToString( - sparse_linear_algebra_library)); - } + StringAppendF(&report, "Threads: % 25d% 25d\n", + num_threads_given, num_threads_used); + StringAppendF(&report, "Linear solver threads % 23d% 25d\n", + num_linear_solver_threads_given, + num_linear_solver_threads_used); + + if (IsSchurType(linear_solver_type_used)) { + string given; + StringifyOrdering(linear_solver_ordering_given, &given); + string used; + StringifyOrdering(linear_solver_ordering_used, &used); + StringAppendF(&report, + "Linear solver ordering %22s %24s\n", + given.c_str(), + used.c_str()); + } + + if (inner_iterations) { + string given; + StringifyOrdering(inner_iteration_ordering_given, &given); + string used; + StringifyOrdering(inner_iteration_ordering_used, &used); + StringAppendF(&report, + "Inner iteration ordering %20s %24s\n", + given.c_str(), + used.c_str()); + } + + if (termination_type == DID_NOT_RUN) { + CHECK(!error.empty()) + << "Solver terminated with DID_NOT_RUN but the solver did not " + << "return a reason. This is a Ceres error. Please report this " + << "to the Ceres team"; + StringAppendF(&report, "Termination: %20s\n", + "DID_NOT_RUN"); + StringAppendF(&report, "Reason: %s\n", error.c_str()); + return report; + } + + StringAppendF(&report, "\nCost:\n"); + StringAppendF(&report, "Initial % 30e\n", initial_cost); + if (termination_type != NUMERICAL_FAILURE && + termination_type != USER_ABORT) { + StringAppendF(&report, "Final % 30e\n", final_cost); + StringAppendF(&report, "Change % 30e\n", + initial_cost - final_cost); + } + + StringAppendF(&report, "\nNumber of iterations:\n"); + StringAppendF(&report, "Successful % 20d\n", + num_successful_steps); + StringAppendF(&report, "Unsuccessful % 20d\n", + num_unsuccessful_steps); + StringAppendF(&report, "Total % 20d\n", + num_successful_steps + num_unsuccessful_steps); + + StringAppendF(&report, "\nTime (in seconds):\n"); + StringAppendF(&report, "Preprocessor %25.3f\n", + preprocessor_time_in_seconds); + StringAppendF(&report, "\n Residual Evaluations %22.3f\n", + residual_evaluation_time_in_seconds); + StringAppendF(&report, " Jacobian Evaluations %22.3f\n", + jacobian_evaluation_time_in_seconds); + StringAppendF(&report, " Linear Solver %23.3f\n", + linear_solver_time_in_seconds); + StringAppendF(&report, "Minimizer %25.3f\n\n", + minimizer_time_in_seconds); + + StringAppendF(&report, "Postprocessor %24.3f\n", + postprocessor_time_in_seconds); - internal::StringAppendF(&report, "Trust Region Strategy %19s", - TrustRegionStrategyTypeToString( - trust_region_strategy_type)); - if (trust_region_strategy_type == DOGLEG) { - if (dogleg_type == TRADITIONAL_DOGLEG) { - internal::StringAppendF(&report, " (TRADITIONAL)"); + StringAppendF(&report, "Total %25.3f\n\n", + total_time_in_seconds); + + StringAppendF(&report, "Termination: %25s\n", + SolverTerminationTypeToString(termination_type)); + } else { + // LINE_SEARCH + StringAppendF(&report, "\nMinimizer %19s\n", "LINE_SEARCH"); + if (line_search_direction_type == LBFGS) { + StringAppendF(&report, "Line search direction %19s(%d)\n", + LineSearchDirectionTypeToString(line_search_direction_type), + max_lbfgs_rank); } else { - internal::StringAppendF(&report, " (SUBSPACE)"); + StringAppendF(&report, "Line search direction %19s\n", + LineSearchDirectionTypeToString( + line_search_direction_type)); } - } - internal::StringAppendF(&report, "\n"); + StringAppendF(&report, "Line search type %19s\n", + LineSearchTypeToString(line_search_type)); + StringAppendF(&report, "\n"); - if (termination_type == DID_NOT_RUN) { - CHECK(!error.empty()) - << "Solver terminated with DID_NOT_RUN but the solver did not " - << "return a reason. This is a Ceres error. Please report this " - << "to the Ceres team"; - internal::StringAppendF(&report, "Termination: %20s\n", - "DID_NOT_RUN"); - internal::StringAppendF(&report, "Reason: %s\n", error.c_str()); - return report; - } + StringAppendF(&report, "%45s %21s\n", "Given", "Used"); + StringAppendF(&report, "Threads: % 25d% 25d\n", + num_threads_given, num_threads_used); - internal::StringAppendF(&report, "\nCost:\n"); - internal::StringAppendF(&report, "Initial % 30e\n", initial_cost); - if (termination_type != NUMERICAL_FAILURE && termination_type != USER_ABORT) { - internal::StringAppendF(&report, "Final % 30e\n", final_cost); - internal::StringAppendF(&report, "Change % 30e\n", - initial_cost - final_cost); + if (termination_type == DID_NOT_RUN) { + CHECK(!error.empty()) + << "Solver terminated with DID_NOT_RUN but the solver did not " + << "return a reason. This is a Ceres error. Please report this " + << "to the Ceres team"; + StringAppendF(&report, "Termination: %20s\n", + "DID_NOT_RUN"); + StringAppendF(&report, "Reason: %s\n", error.c_str()); + return report; + } + + StringAppendF(&report, "\nCost:\n"); + StringAppendF(&report, "Initial % 30e\n", initial_cost); + if (termination_type != NUMERICAL_FAILURE && + termination_type != USER_ABORT) { + StringAppendF(&report, "Final % 30e\n", final_cost); + StringAppendF(&report, "Change % 30e\n", + initial_cost - final_cost); + } + + StringAppendF(&report, "\nNumber of iterations: % 20ld\n", + iterations.size() - 1); + + StringAppendF(&report, "\nTime (in seconds):\n"); + StringAppendF(&report, "Preprocessor %25.3f\n", + preprocessor_time_in_seconds); + StringAppendF(&report, "\n Residual Evaluations %22.3f\n", + residual_evaluation_time_in_seconds); + StringAppendF(&report, " Jacobian Evaluations %22.3f\n", + jacobian_evaluation_time_in_seconds); + StringAppendF(&report, "Minimizer %25.3f\n\n", + minimizer_time_in_seconds); + + StringAppendF(&report, "Postprocessor %24.3f\n", + postprocessor_time_in_seconds); + + StringAppendF(&report, "Total %25.3f\n\n", + total_time_in_seconds); + + StringAppendF(&report, "Termination: %25s\n", + SolverTerminationTypeToString(termination_type)); } - internal::StringAppendF(&report, "\nNumber of iterations:\n"); - internal::StringAppendF(&report, "Successful % 20d\n", - num_successful_steps); - internal::StringAppendF(&report, "Unsuccessful % 20d\n", - num_unsuccessful_steps); - internal::StringAppendF(&report, "Total % 20d\n", - num_successful_steps + num_unsuccessful_steps); - internal::StringAppendF(&report, "\nTime (in seconds):\n"); - internal::StringAppendF(&report, "Preprocessor % 25e\n", - preprocessor_time_in_seconds); - internal::StringAppendF(&report, "Minimizer % 25e\n", - minimizer_time_in_seconds); - internal::StringAppendF(&report, "Total % 25e\n", - total_time_in_seconds); - - internal::StringAppendF(&report, "Termination: %25s\n", - SolverTerminationTypeToString(termination_type)); return report; }; diff --git a/extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc b/extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc index 8ef5b98e35f..5bcfdc6312f 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc @@ -33,21 +33,25 @@ #include #include // NOLINT #include +#include "ceres/coordinate_descent_minimizer.h" #include "ceres/evaluator.h" #include "ceres/gradient_checking_cost_function.h" #include "ceres/iteration_callback.h" #include "ceres/levenberg_marquardt_strategy.h" #include "ceres/linear_solver.h" +#include "ceres/line_search_minimizer.h" #include "ceres/map_util.h" #include "ceres/minimizer.h" +#include "ceres/ordered_groups.h" #include "ceres/parameter_block.h" +#include "ceres/parameter_block_ordering.h" #include "ceres/problem.h" #include "ceres/problem_impl.h" #include "ceres/program.h" #include "ceres/residual_block.h" -#include "ceres/schur_ordering.h" #include "ceres/stringprintf.h" #include "ceres/trust_region_minimizer.h" +#include "ceres/wall_time.h" namespace ceres { namespace internal { @@ -73,14 +77,24 @@ class StateUpdatingCallback : public IterationCallback { double* parameters_; }; +void SetSummaryFinalCost(Solver::Summary* summary) { + summary->final_cost = summary->initial_cost; + // We need the loop here, instead of just looking at the last + // iteration because the minimizer maybe making non-monotonic steps. + for (int i = 0; i < summary->iterations.size(); ++i) { + const IterationSummary& iteration_summary = summary->iterations[i]; + summary->final_cost = min(iteration_summary.cost, summary->final_cost); + } +} + // Callback for logging the state of the minimizer to STDERR or STDOUT // depending on the user's preferences and logging level. -class LoggingCallback : public IterationCallback { +class TrustRegionLoggingCallback : public IterationCallback { public: - explicit LoggingCallback(bool log_to_stdout) + explicit TrustRegionLoggingCallback(bool log_to_stdout) : log_to_stdout_(log_to_stdout) {} - ~LoggingCallback() {} + ~TrustRegionLoggingCallback() {} CallbackReturnType operator()(const IterationSummary& summary) { const char* kReportRowFormat = @@ -109,6 +123,42 @@ class LoggingCallback : public IterationCallback { const bool log_to_stdout_; }; +// Callback for logging the state of the minimizer to STDERR or STDOUT +// depending on the user's preferences and logging level. +class LineSearchLoggingCallback : public IterationCallback { + public: + explicit LineSearchLoggingCallback(bool log_to_stdout) + : log_to_stdout_(log_to_stdout) {} + + ~LineSearchLoggingCallback() {} + + CallbackReturnType operator()(const IterationSummary& summary) { + const char* kReportRowFormat = + "% 4d: f:% 8e d:% 3.2e g:% 3.2e h:% 3.2e " + "s:% 3.2e e:% 3d it:% 3.2e tt:% 3.2e"; + string output = StringPrintf(kReportRowFormat, + summary.iteration, + summary.cost, + summary.cost_change, + summary.gradient_max_norm, + summary.step_norm, + summary.step_size, + summary.line_search_function_evaluations, + summary.iteration_time_in_seconds, + summary.cumulative_time_in_seconds); + if (log_to_stdout_) { + cout << output << endl; + } else { + VLOG(1) << output; + } + return SOLVER_CONTINUE; + } + + private: + const bool log_to_stdout_; +}; + + // Basic callback to record the execution of the solver to a file for // offline analysis. class FileLoggingCallback : public IterationCallback { @@ -137,14 +187,34 @@ class FileLoggingCallback : public IterationCallback { FILE* fptr_; }; +// Iterate over each of the groups in order of their priority and fill +// summary with their sizes. +void SummarizeOrdering(ParameterBlockOrdering* ordering, + vector* summary) { + CHECK_NOTNULL(summary)->clear(); + if (ordering == NULL) { + return; + } + + const map >& group_to_elements = + ordering->group_to_elements(); + for (map >::const_iterator it = group_to_elements.begin(); + it != group_to_elements.end(); + ++it) { + summary->push_back(it->second.size()); + } +} + } // namespace -void SolverImpl::Minimize(const Solver::Options& options, - Program* program, - Evaluator* evaluator, - LinearSolver* linear_solver, - double* parameters, - Solver::Summary* summary) { +void SolverImpl::TrustRegionMinimize( + const Solver::Options& options, + Program* program, + CoordinateDescentMinimizer* inner_iteration_minimizer, + Evaluator* evaluator, + LinearSolver* linear_solver, + double* parameters, + Solver::Summary* summary) { Minimizer::Options minimizer_options(options); // TODO(sameeragarwal): Add support for logging the configuration @@ -156,7 +226,8 @@ void SolverImpl::Minimize(const Solver::Options& options, file_logging_callback.get()); } - LoggingCallback logging_callback(options.minimizer_progress_to_stdout); + TrustRegionLoggingCallback logging_callback( + options.minimizer_progress_to_stdout); if (options.logging_type != SILENT) { minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(), &logging_callback); @@ -172,7 +243,9 @@ void SolverImpl::Minimize(const Solver::Options& options, minimizer_options.evaluator = evaluator; scoped_ptr jacobian(evaluator->CreateJacobian()); + minimizer_options.jacobian = jacobian.get(); + minimizer_options.inner_iteration_minimizer = inner_iteration_minimizer; TrustRegionStrategy::Options trust_region_strategy_options; trust_region_strategy_options.linear_solver = linear_solver; @@ -189,78 +262,140 @@ void SolverImpl::Minimize(const Solver::Options& options, minimizer_options.trust_region_strategy = strategy.get(); TrustRegionMinimizer minimizer; - time_t minimizer_start_time = time(NULL); + double minimizer_start_time = WallTimeInSeconds(); minimizer.Minimize(minimizer_options, parameters, summary); - summary->minimizer_time_in_seconds = time(NULL) - minimizer_start_time; + summary->minimizer_time_in_seconds = + WallTimeInSeconds() - minimizer_start_time; } -void SolverImpl::Solve(const Solver::Options& original_options, - ProblemImpl* original_problem_impl, + +void SolverImpl::LineSearchMinimize( + const Solver::Options& options, + Program* program, + Evaluator* evaluator, + double* parameters, + Solver::Summary* summary) { + Minimizer::Options minimizer_options(options); + + // TODO(sameeragarwal): Add support for logging the configuration + // and more detailed stats. + scoped_ptr file_logging_callback; + if (!options.solver_log.empty()) { + file_logging_callback.reset(new FileLoggingCallback(options.solver_log)); + minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(), + file_logging_callback.get()); + } + + LineSearchLoggingCallback logging_callback( + options.minimizer_progress_to_stdout); + if (options.logging_type != SILENT) { + minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(), + &logging_callback); + } + + StateUpdatingCallback updating_callback(program, parameters); + if (options.update_state_every_iteration) { + // This must get pushed to the front of the callbacks so that it is run + // before any of the user callbacks. + minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(), + &updating_callback); + } + + minimizer_options.evaluator = evaluator; + + LineSearchMinimizer minimizer; + double minimizer_start_time = WallTimeInSeconds(); + minimizer.Minimize(minimizer_options, parameters, summary); + summary->minimizer_time_in_seconds = + WallTimeInSeconds() - minimizer_start_time; +} + +void SolverImpl::Solve(const Solver::Options& options, + ProblemImpl* problem_impl, Solver::Summary* summary) { - time_t solver_start_time = time(NULL); - Solver::Options options(original_options); + if (options.minimizer_type == TRUST_REGION) { + TrustRegionSolve(options, problem_impl, summary); + } else { + LineSearchSolve(options, problem_impl, summary); + } +} + +void SolverImpl::TrustRegionSolve(const Solver::Options& original_options, + ProblemImpl* original_problem_impl, + Solver::Summary* summary) { + EventLogger event_logger("TrustRegionSolve"); + double solver_start_time = WallTimeInSeconds(); + Program* original_program = original_problem_impl->mutable_program(); ProblemImpl* problem_impl = original_problem_impl; + // Reset the summary object to its default values. *CHECK_NOTNULL(summary) = Solver::Summary(); + summary->minimizer_type = TRUST_REGION; + summary->num_parameter_blocks = problem_impl->NumParameterBlocks(); + summary->num_parameters = problem_impl->NumParameters(); + summary->num_residual_blocks = problem_impl->NumResidualBlocks(); + summary->num_residuals = problem_impl->NumResiduals(); + + // Empty programs are usually a user error. + if (summary->num_parameter_blocks == 0) { + summary->error = "Problem contains no parameter blocks."; + LOG(ERROR) << summary->error; + return; + } + + if (summary->num_residual_blocks == 0) { + summary->error = "Problem contains no residual blocks."; + LOG(ERROR) << summary->error; + return; + } + + SummarizeOrdering(original_options.linear_solver_ordering, + &(summary->linear_solver_ordering_given)); + + SummarizeOrdering(original_options.inner_iteration_ordering, + &(summary->inner_iteration_ordering_given)); + + Solver::Options options(original_options); + options.linear_solver_ordering = NULL; + options.inner_iteration_ordering = NULL; #ifndef CERES_USE_OPENMP if (options.num_threads > 1) { LOG(WARNING) << "OpenMP support is not compiled into this binary; " - << "only options.num_threads=1 is supported. Switching" + << "only options.num_threads=1 is supported. Switching " << "to single threaded mode."; options.num_threads = 1; } if (options.num_linear_solver_threads > 1) { LOG(WARNING) << "OpenMP support is not compiled into this binary; " - << "only options.num_linear_solver_threads=1 is supported. Switching" + << "only options.num_linear_solver_threads=1 is supported. Switching " << "to single threaded mode."; options.num_linear_solver_threads = 1; } #endif - summary->linear_solver_type_given = options.linear_solver_type; - summary->num_eliminate_blocks_given = original_options.num_eliminate_blocks; summary->num_threads_given = original_options.num_threads; - summary->num_linear_solver_threads_given = - original_options.num_linear_solver_threads; - summary->ordering_type = original_options.ordering_type; + summary->num_threads_used = options.num_threads; - summary->num_parameter_blocks = problem_impl->NumParameterBlocks(); - summary->num_parameters = problem_impl->NumParameters(); - summary->num_residual_blocks = problem_impl->NumResidualBlocks(); - summary->num_residuals = problem_impl->NumResiduals(); + if (options.lsqp_iterations_to_dump.size() > 0) { + LOG(WARNING) << "Dumping linear least squares problems to disk is" + " currently broken. Ignoring Solver::Options::lsqp_iterations_to_dump"; + } - summary->num_threads_used = options.num_threads; - summary->sparse_linear_algebra_library = - options.sparse_linear_algebra_library; - summary->trust_region_strategy_type = options.trust_region_strategy_type; - summary->dogleg_type = options.dogleg_type; + event_logger.AddEvent("Init"); - // Evaluate the initial cost, residual vector and the jacobian - // matrix if requested by the user. The initial cost needs to be - // computed on the original unpreprocessed problem, as it is used to - // determine the value of the "fixed" part of the objective function - // after the problem has undergone reduction. - Evaluator::Evaluate( - original_program, - options.num_threads, - &(summary->initial_cost), - options.return_initial_residuals ? &summary->initial_residuals : NULL, - options.return_initial_gradient ? &summary->initial_gradient : NULL, - options.return_initial_jacobian ? &summary->initial_jacobian : NULL); - original_program->SetParameterBlockStatePtrsToUserStatePtrs(); + original_program->SetParameterBlockStatePtrsToUserStatePtrs(); + event_logger.AddEvent("SetParameterBlockPtrs"); // If the user requests gradient checking, construct a new // ProblemImpl by wrapping the CostFunctions of problem_impl inside // GradientCheckingCostFunction and replacing problem_impl with // gradient_checking_problem_impl. scoped_ptr gradient_checking_problem_impl; - // Save the original problem impl so we don't use the gradient - // checking one when computing the residuals. if (options.check_gradients) { VLOG(1) << "Checking Gradients"; gradient_checking_problem_impl.reset( @@ -269,45 +404,344 @@ void SolverImpl::Solve(const Solver::Options& original_options, options.numeric_derivative_relative_step_size, options.gradient_check_relative_precision)); - // From here on, problem_impl will point to the GradientChecking version. + // From here on, problem_impl will point to the gradient checking + // version. problem_impl = gradient_checking_problem_impl.get(); } + if (original_options.linear_solver_ordering != NULL) { + if (!IsOrderingValid(original_options, problem_impl, &summary->error)) { + LOG(ERROR) << summary->error; + return; + } + event_logger.AddEvent("CheckOrdering"); + options.linear_solver_ordering = + new ParameterBlockOrdering(*original_options.linear_solver_ordering); + event_logger.AddEvent("CopyOrdering"); + } else { + options.linear_solver_ordering = new ParameterBlockOrdering; + const ProblemImpl::ParameterMap& parameter_map = + problem_impl->parameter_map(); + for (ProblemImpl::ParameterMap::const_iterator it = parameter_map.begin(); + it != parameter_map.end(); + ++it) { + options.linear_solver_ordering->AddElementToGroup(it->first, 0); + } + event_logger.AddEvent("ConstructOrdering"); + } + // Create the three objects needed to minimize: the transformed program, the // evaluator, and the linear solver. - scoped_ptr reduced_program(CreateReducedProgram(&options, problem_impl, &summary->fixed_cost, &summary->error)); + + event_logger.AddEvent("CreateReducedProgram"); if (reduced_program == NULL) { return; } + SummarizeOrdering(options.linear_solver_ordering, + &(summary->linear_solver_ordering_used)); + summary->num_parameter_blocks_reduced = reduced_program->NumParameterBlocks(); summary->num_parameters_reduced = reduced_program->NumParameters(); summary->num_residual_blocks_reduced = reduced_program->NumResidualBlocks(); summary->num_residuals_reduced = reduced_program->NumResiduals(); + if (summary->num_parameter_blocks_reduced == 0) { + summary->preprocessor_time_in_seconds = + WallTimeInSeconds() - solver_start_time; + + double post_process_start_time = WallTimeInSeconds(); + LOG(INFO) << "Terminating: FUNCTION_TOLERANCE reached. " + << "No non-constant parameter blocks found."; + + summary->initial_cost = summary->fixed_cost; + summary->final_cost = summary->fixed_cost; + + // FUNCTION_TOLERANCE is the right convergence here, as we know + // that the objective function is constant and cannot be changed + // any further. + summary->termination_type = FUNCTION_TOLERANCE; + + // Ensure the program state is set to the user parameters on the way out. + original_program->SetParameterBlockStatePtrsToUserStatePtrs(); + + summary->postprocessor_time_in_seconds = + WallTimeInSeconds() - post_process_start_time; + return; + } + scoped_ptr linear_solver(CreateLinearSolver(&options, &summary->error)); + event_logger.AddEvent("CreateLinearSolver"); + if (linear_solver == NULL) { + return; + } + + summary->linear_solver_type_given = original_options.linear_solver_type; summary->linear_solver_type_used = options.linear_solver_type; + summary->preconditioner_type = options.preconditioner_type; - summary->num_eliminate_blocks_used = options.num_eliminate_blocks; + + summary->num_linear_solver_threads_given = + original_options.num_linear_solver_threads; summary->num_linear_solver_threads_used = options.num_linear_solver_threads; - if (linear_solver == NULL) { + summary->sparse_linear_algebra_library = + options.sparse_linear_algebra_library; + + summary->trust_region_strategy_type = options.trust_region_strategy_type; + summary->dogleg_type = options.dogleg_type; + + // Only Schur types require the lexicographic reordering. + if (IsSchurType(options.linear_solver_type)) { + const int num_eliminate_blocks = + options.linear_solver_ordering + ->group_to_elements().begin() + ->second.size(); + if (!LexicographicallyOrderResidualBlocks(num_eliminate_blocks, + reduced_program.get(), + &summary->error)) { + return; + } + } + + scoped_ptr evaluator(CreateEvaluator(options, + problem_impl->parameter_map(), + reduced_program.get(), + &summary->error)); + + event_logger.AddEvent("CreateEvaluator"); + + if (evaluator == NULL) { + return; + } + + scoped_ptr inner_iteration_minimizer; + if (options.use_inner_iterations) { + if (reduced_program->parameter_blocks().size() < 2) { + LOG(WARNING) << "Reduced problem only contains one parameter block." + << "Disabling inner iterations."; + } else { + inner_iteration_minimizer.reset( + CreateInnerIterationMinimizer(original_options, + *reduced_program, + problem_impl->parameter_map(), + summary)); + if (inner_iteration_minimizer == NULL) { + LOG(ERROR) << summary->error; + return; + } + } + } + + event_logger.AddEvent("CreateIIM"); + + // The optimizer works on contiguous parameter vectors; allocate some. + Vector parameters(reduced_program->NumParameters()); + + // Collect the discontiguous parameters into a contiguous state vector. + reduced_program->ParameterBlocksToStateVector(parameters.data()); + + Vector original_parameters = parameters; + + double minimizer_start_time = WallTimeInSeconds(); + summary->preprocessor_time_in_seconds = + minimizer_start_time - solver_start_time; + + // Run the optimization. + TrustRegionMinimize(options, + reduced_program.get(), + inner_iteration_minimizer.get(), + evaluator.get(), + linear_solver.get(), + parameters.data(), + summary); + event_logger.AddEvent("Minimize"); + + SetSummaryFinalCost(summary); + + // If the user aborted mid-optimization or the optimization + // terminated because of a numerical failure, then return without + // updating user state. + if (summary->termination_type == USER_ABORT || + summary->termination_type == NUMERICAL_FAILURE) { return; } - if (!MaybeReorderResidualBlocks(options, - reduced_program.get(), - &summary->error)) { + double post_process_start_time = WallTimeInSeconds(); + + // Push the contiguous optimized parameters back to the user's + // parameters. + reduced_program->StateVectorToParameterBlocks(parameters.data()); + reduced_program->CopyParameterBlockStateToUserState(); + + // Ensure the program state is set to the user parameters on the way + // out. + original_program->SetParameterBlockStatePtrsToUserStatePtrs(); + + const map& linear_solver_time_statistics = + linear_solver->TimeStatistics(); + summary->linear_solver_time_in_seconds = + FindWithDefault(linear_solver_time_statistics, + "LinearSolver::Solve", + 0.0); + + const map& evaluator_time_statistics = + evaluator->TimeStatistics(); + + summary->residual_evaluation_time_in_seconds = + FindWithDefault(evaluator_time_statistics, "Evaluator::Residual", 0.0); + summary->jacobian_evaluation_time_in_seconds = + FindWithDefault(evaluator_time_statistics, "Evaluator::Jacobian", 0.0); + + // Stick a fork in it, we're done. + summary->postprocessor_time_in_seconds = + WallTimeInSeconds() - post_process_start_time; + event_logger.AddEvent("PostProcess"); +} + +void SolverImpl::LineSearchSolve(const Solver::Options& original_options, + ProblemImpl* original_problem_impl, + Solver::Summary* summary) { + double solver_start_time = WallTimeInSeconds(); + + Program* original_program = original_problem_impl->mutable_program(); + ProblemImpl* problem_impl = original_problem_impl; + + // Reset the summary object to its default values. + *CHECK_NOTNULL(summary) = Solver::Summary(); + + summary->minimizer_type = LINE_SEARCH; + summary->line_search_direction_type = + original_options.line_search_direction_type; + summary->max_lbfgs_rank = original_options.max_lbfgs_rank; + summary->line_search_type = original_options.line_search_type; + summary->num_parameter_blocks = problem_impl->NumParameterBlocks(); + summary->num_parameters = problem_impl->NumParameters(); + summary->num_residual_blocks = problem_impl->NumResidualBlocks(); + summary->num_residuals = problem_impl->NumResiduals(); + + // Empty programs are usually a user error. + if (summary->num_parameter_blocks == 0) { + summary->error = "Problem contains no parameter blocks."; + LOG(ERROR) << summary->error; return; } - scoped_ptr evaluator( - CreateEvaluator(options, reduced_program.get(), &summary->error)); + if (summary->num_residual_blocks == 0) { + summary->error = "Problem contains no residual blocks."; + LOG(ERROR) << summary->error; + return; + } + + Solver::Options options(original_options); + + // This ensures that we get a Block Jacobian Evaluator along with + // none of the Schur nonsense. This file will have to be extensively + // refactored to deal with the various bits of cleanups related to + // line search. + options.linear_solver_type = CGNR; + + options.linear_solver_ordering = NULL; + options.inner_iteration_ordering = NULL; + +#ifndef CERES_USE_OPENMP + if (options.num_threads > 1) { + LOG(WARNING) + << "OpenMP support is not compiled into this binary; " + << "only options.num_threads=1 is supported. Switching " + << "to single threaded mode."; + options.num_threads = 1; + } +#endif + + summary->num_threads_given = original_options.num_threads; + summary->num_threads_used = options.num_threads; + + if (original_options.linear_solver_ordering != NULL) { + if (!IsOrderingValid(original_options, problem_impl, &summary->error)) { + LOG(ERROR) << summary->error; + return; + } + options.linear_solver_ordering = + new ParameterBlockOrdering(*original_options.linear_solver_ordering); + } else { + options.linear_solver_ordering = new ParameterBlockOrdering; + const ProblemImpl::ParameterMap& parameter_map = + problem_impl->parameter_map(); + for (ProblemImpl::ParameterMap::const_iterator it = parameter_map.begin(); + it != parameter_map.end(); + ++it) { + options.linear_solver_ordering->AddElementToGroup(it->first, 0); + } + } + + original_program->SetParameterBlockStatePtrsToUserStatePtrs(); + + // If the user requests gradient checking, construct a new + // ProblemImpl by wrapping the CostFunctions of problem_impl inside + // GradientCheckingCostFunction and replacing problem_impl with + // gradient_checking_problem_impl. + scoped_ptr gradient_checking_problem_impl; + if (options.check_gradients) { + VLOG(1) << "Checking Gradients"; + gradient_checking_problem_impl.reset( + CreateGradientCheckingProblemImpl( + problem_impl, + options.numeric_derivative_relative_step_size, + options.gradient_check_relative_precision)); + + // From here on, problem_impl will point to the gradient checking + // version. + problem_impl = gradient_checking_problem_impl.get(); + } + + // Create the three objects needed to minimize: the transformed program, the + // evaluator, and the linear solver. + scoped_ptr reduced_program(CreateReducedProgram(&options, + problem_impl, + &summary->fixed_cost, + &summary->error)); + if (reduced_program == NULL) { + return; + } + + summary->num_parameter_blocks_reduced = reduced_program->NumParameterBlocks(); + summary->num_parameters_reduced = reduced_program->NumParameters(); + summary->num_residual_blocks_reduced = reduced_program->NumResidualBlocks(); + summary->num_residuals_reduced = reduced_program->NumResiduals(); + + if (summary->num_parameter_blocks_reduced == 0) { + summary->preprocessor_time_in_seconds = + WallTimeInSeconds() - solver_start_time; + + LOG(INFO) << "Terminating: FUNCTION_TOLERANCE reached. " + << "No non-constant parameter blocks found."; + + // FUNCTION_TOLERANCE is the right convergence here, as we know + // that the objective function is constant and cannot be changed + // any further. + summary->termination_type = FUNCTION_TOLERANCE; + + const double post_process_start_time = WallTimeInSeconds(); + + SetSummaryFinalCost(summary); + + // Ensure the program state is set to the user parameters on the way out. + original_program->SetParameterBlockStatePtrsToUserStatePtrs(); + summary->postprocessor_time_in_seconds = + WallTimeInSeconds() - post_process_start_time; + return; + } + + scoped_ptr evaluator(CreateEvaluator(options, + problem_impl->parameter_map(), + reduced_program.get(), + &summary->error)); if (evaluator == NULL) { return; } @@ -318,17 +752,18 @@ void SolverImpl::Solve(const Solver::Options& original_options, // Collect the discontiguous parameters into a contiguous state vector. reduced_program->ParameterBlocksToStateVector(parameters.data()); - time_t minimizer_start_time = time(NULL); + Vector original_parameters = parameters; + + const double minimizer_start_time = WallTimeInSeconds(); summary->preprocessor_time_in_seconds = minimizer_start_time - solver_start_time; // Run the optimization. - Minimize(options, - reduced_program.get(), - evaluator.get(), - linear_solver.get(), - parameters.data(), - summary); + LineSearchMinimize(options, + reduced_program.get(), + evaluator.get(), + parameters.data(), + summary); // If the user aborted mid-optimization or the optimization // terminated because of a numerical failure, then return without @@ -338,35 +773,100 @@ void SolverImpl::Solve(const Solver::Options& original_options, return; } - time_t post_process_start_time = time(NULL); + const double post_process_start_time = WallTimeInSeconds(); // Push the contiguous optimized parameters back to the user's parameters. reduced_program->StateVectorToParameterBlocks(parameters.data()); reduced_program->CopyParameterBlockStateToUserState(); - // Evaluate the final cost, residual vector and the jacobian - // matrix if requested by the user. - Evaluator::Evaluate( - original_program, - options.num_threads, - &summary->final_cost, - options.return_final_residuals ? &summary->final_residuals : NULL, - options.return_final_gradient ? &summary->final_gradient : NULL, - options.return_final_jacobian ? &summary->final_jacobian : NULL); + SetSummaryFinalCost(summary); // Ensure the program state is set to the user parameters on the way out. original_program->SetParameterBlockStatePtrsToUserStatePtrs(); + + const map& evaluator_time_statistics = + evaluator->TimeStatistics(); + + summary->residual_evaluation_time_in_seconds = + FindWithDefault(evaluator_time_statistics, "Evaluator::Residual", 0.0); + summary->jacobian_evaluation_time_in_seconds = + FindWithDefault(evaluator_time_statistics, "Evaluator::Jacobian", 0.0); + // Stick a fork in it, we're done. - summary->postprocessor_time_in_seconds = time(NULL) - post_process_start_time; + summary->postprocessor_time_in_seconds = + WallTimeInSeconds() - post_process_start_time; +} + + +bool SolverImpl::IsOrderingValid(const Solver::Options& options, + const ProblemImpl* problem_impl, + string* error) { + if (options.linear_solver_ordering->NumElements() != + problem_impl->NumParameterBlocks()) { + *error = "Number of parameter blocks in user supplied ordering " + "does not match the number of parameter blocks in the problem"; + return false; + } + + const Program& program = problem_impl->program(); + const vector& parameter_blocks = program.parameter_blocks(); + for (vector::const_iterator it = parameter_blocks.begin(); + it != parameter_blocks.end(); + ++it) { + if (!options.linear_solver_ordering + ->IsMember(const_cast((*it)->user_state()))) { + *error = "Problem contains a parameter block that is not in " + "the user specified ordering."; + return false; + } + } + + if (IsSchurType(options.linear_solver_type) && + options.linear_solver_ordering->NumGroups() > 1) { + const vector& residual_blocks = program.residual_blocks(); + const set& e_blocks = + options.linear_solver_ordering->group_to_elements().begin()->second; + if (!IsParameterBlockSetIndependent(e_blocks, residual_blocks)) { + *error = "The user requested the use of a Schur type solver. " + "But the first elimination group in the ordering is not an " + "independent set."; + return false; + } + } + return true; +} + +bool SolverImpl::IsParameterBlockSetIndependent( + const set& parameter_block_ptrs, + const vector& residual_blocks) { + // Loop over each residual block and ensure that no two parameter + // blocks in the same residual block are part of + // parameter_block_ptrs as that would violate the assumption that it + // is an independent set in the Hessian matrix. + for (vector::const_iterator it = residual_blocks.begin(); + it != residual_blocks.end(); + ++it) { + ParameterBlock* const* parameter_blocks = (*it)->parameter_blocks(); + const int num_parameter_blocks = (*it)->NumParameterBlocks(); + int count = 0; + for (int i = 0; i < num_parameter_blocks; ++i) { + count += parameter_block_ptrs.count( + parameter_blocks[i]->mutable_user_state()); + } + if (count > 1) { + return false; + } + } + return true; } + // Strips varying parameters and residuals, maintaining order, and updating // num_eliminate_blocks. bool SolverImpl::RemoveFixedBlocksFromProgram(Program* program, - int* num_eliminate_blocks, + ParameterBlockOrdering* ordering, double* fixed_cost, string* error) { - int original_num_eliminate_blocks = *num_eliminate_blocks; vector* parameter_blocks = program->mutable_parameter_blocks(); @@ -423,7 +923,7 @@ bool SolverImpl::RemoveFixedBlocksFromProgram(Program* program, } // Filter out unused or fixed parameter blocks, and update - // num_eliminate_blocks as necessary. + // the ordering. { vector* parameter_blocks = program->mutable_parameter_blocks(); @@ -432,8 +932,8 @@ bool SolverImpl::RemoveFixedBlocksFromProgram(Program* program, ParameterBlock* parameter_block = (*parameter_blocks)[i]; if (parameter_block->index() == 1) { (*parameter_blocks)[j++] = parameter_block; - } else if (i < original_num_eliminate_blocks) { - (*num_eliminate_blocks)--; + } else { + ordering->Remove(parameter_block->mutable_user_state()); } } parameter_blocks->resize(j); @@ -451,70 +951,127 @@ Program* SolverImpl::CreateReducedProgram(Solver::Options* options, ProblemImpl* problem_impl, double* fixed_cost, string* error) { + EventLogger event_logger("CreateReducedProgram"); + + CHECK_NOTNULL(options->linear_solver_ordering); Program* original_program = problem_impl->mutable_program(); scoped_ptr transformed_program(new Program(*original_program)); + event_logger.AddEvent("TransformedProgram"); - if (options->ordering_type == USER && - !ApplyUserOrdering(*problem_impl, - options->ordering, - transformed_program.get(), - error)) { - return NULL; - } - - if (options->ordering_type == SCHUR && options->num_eliminate_blocks != 0) { - *error = "Can't specify SCHUR ordering and num_eliminate_blocks " - "at the same time; SCHUR ordering determines " - "num_eliminate_blocks automatically."; - return NULL; - } - - if (options->ordering_type == SCHUR && options->ordering.size() != 0) { - *error = "Can't specify SCHUR ordering type and the ordering " - "vector at the same time; SCHUR ordering determines " - "a suitable parameter ordering automatically."; - return NULL; - } + ParameterBlockOrdering* linear_solver_ordering = + options->linear_solver_ordering; - int num_eliminate_blocks = options->num_eliminate_blocks; + const int min_group_id = + linear_solver_ordering->group_to_elements().begin()->first; + const int original_num_groups = linear_solver_ordering->NumGroups(); if (!RemoveFixedBlocksFromProgram(transformed_program.get(), - &num_eliminate_blocks, + linear_solver_ordering, fixed_cost, error)) { return NULL; } + event_logger.AddEvent("RemoveFixedBlocks"); + if (transformed_program->NumParameterBlocks() == 0) { + if (transformed_program->NumResidualBlocks() > 0) { + *error = "Zero parameter blocks but non-zero residual blocks" + " in the reduced program. Congratulations, you found a " + "Ceres bug! Please report this error to the developers."; + return NULL; + } + LOG(WARNING) << "No varying parameter blocks to optimize; " << "bailing early."; return transformed_program.release(); } - if (options->ordering_type == SCHUR) { + // If the user supplied an linear_solver_ordering with just one + // group, it is equivalent to the user supplying NULL as + // ordering. Ceres is completely free to choose the parameter block + // ordering as it sees fit. For Schur type solvers, this means that + // the user wishes for Ceres to identify the e_blocks, which we do + // by computing a maximal independent set. + if (original_num_groups == 1 && IsSchurType(options->linear_solver_type)) { vector schur_ordering; - num_eliminate_blocks = ComputeSchurOrdering(*transformed_program, - &schur_ordering); + const int num_eliminate_blocks = ComputeSchurOrdering(*transformed_program, + &schur_ordering); CHECK_EQ(schur_ordering.size(), transformed_program->NumParameterBlocks()) << "Congratulations, you found a Ceres bug! Please report this error " << "to the developers."; - // Replace the transformed program's ordering with the schur ordering. - swap(*transformed_program->mutable_parameter_blocks(), schur_ordering); + for (int i = 0; i < schur_ordering.size(); ++i) { + linear_solver_ordering->AddElementToGroup( + schur_ordering[i]->mutable_user_state(), + (i < num_eliminate_blocks) ? 0 : 1); + } } - options->num_eliminate_blocks = num_eliminate_blocks; - CHECK_GE(options->num_eliminate_blocks, 0) - << "Congratulations, you found a Ceres bug! Please report this error " - << "to the developers."; + event_logger.AddEvent("SchurOrdering"); + + if (!ApplyUserOrdering(problem_impl->parameter_map(), + linear_solver_ordering, + transformed_program.get(), + error)) { + return NULL; + } + event_logger.AddEvent("ApplyOrdering"); + + // If the user requested the use of a Schur type solver, and + // supplied a non-NULL linear_solver_ordering object with more than + // one elimination group, then it can happen that after all the + // parameter blocks which are fixed or unused have been removed from + // the program and the ordering, there are no more parameter blocks + // in the first elimination group. + // + // In such a case, the use of a Schur type solver is not possible, + // as they assume there is at least one e_block. Thus, we + // automatically switch to one of the other solvers, depending on + // the user's indicated preferences. + if (IsSchurType(options->linear_solver_type) && + original_num_groups > 1 && + linear_solver_ordering->GroupSize(min_group_id) == 0) { + string msg = "No e_blocks remaining. Switching from "; + if (options->linear_solver_type == SPARSE_SCHUR) { + options->linear_solver_type = SPARSE_NORMAL_CHOLESKY; + msg += "SPARSE_SCHUR to SPARSE_NORMAL_CHOLESKY."; + } else if (options->linear_solver_type == DENSE_SCHUR) { + // TODO(sameeragarwal): This is probably not a great choice. + // Ideally, we should have a DENSE_NORMAL_CHOLESKY, that can + // take a BlockSparseMatrix as input. + options->linear_solver_type = DENSE_QR; + msg += "DENSE_SCHUR to DENSE_QR."; + } else if (options->linear_solver_type == ITERATIVE_SCHUR) { + msg += StringPrintf("ITERATIVE_SCHUR with %s preconditioner " + "to CGNR with JACOBI preconditioner.", + PreconditionerTypeToString( + options->preconditioner_type)); + options->linear_solver_type = CGNR; + if (options->preconditioner_type != IDENTITY) { + // CGNR currently only supports the JACOBI preconditioner. + options->preconditioner_type = JACOBI; + } + } - // Since the transformed program is the "active" program, and it is mutated, - // update the parameter offsets and indices. + LOG(WARNING) << msg; + } + + event_logger.AddEvent("AlternateSolver"); + + // Since the transformed program is the "active" program, and it is + // mutated, update the parameter offsets and indices. transformed_program->SetParameterOffsetsAndIndex(); + + event_logger.AddEvent("SetOffsets"); return transformed_program.release(); } LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options, string* error) { + CHECK_NOTNULL(options); + CHECK_NOTNULL(options->linear_solver_ordering); + CHECK_NOTNULL(error); + if (options->trust_region_strategy_type == DOGLEG) { if (options->linear_solver_type == ITERATIVE_SCHUR || options->linear_solver_type == CGNR) { @@ -532,6 +1089,18 @@ LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options, "SuiteSparse was not enabled when Ceres was built."; return NULL; } + + if (options->preconditioner_type == CLUSTER_JACOBI) { + *error = "CLUSTER_JACOBI preconditioner not suppored. Please build Ceres " + "with SuiteSparse support."; + return NULL; + } + + if (options->preconditioner_type == CLUSTER_TRIDIAGONAL) { + *error = "CLUSTER_TRIDIAGONAL preconditioner not suppored. Please build " + "Ceres with SuiteSparse support."; + return NULL; + } #endif #ifdef CERES_NO_CXSPARSE @@ -543,6 +1112,13 @@ LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options, } #endif +#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE) + if (options->linear_solver_type == SPARSE_SCHUR) { + *error = "Can't use SPARSE_SCHUR because neither SuiteSparse nor" + "CXSparse was enabled when Ceres was compiled."; + return NULL; + } +#endif if (options->linear_solver_max_num_iterations <= 0) { *error = "Solver::Options::linear_solver_max_num_iterations is 0."; @@ -568,52 +1144,8 @@ LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options, linear_solver_options.preconditioner_type = options->preconditioner_type; linear_solver_options.sparse_linear_algebra_library = options->sparse_linear_algebra_library; - linear_solver_options.use_block_amd = options->use_block_amd; - -#ifdef CERES_NO_SUITESPARSE - if (linear_solver_options.preconditioner_type == SCHUR_JACOBI) { - *error = "SCHUR_JACOBI preconditioner not suppored. Please build Ceres " - "with SuiteSparse support."; - return NULL; - } - - if (linear_solver_options.preconditioner_type == CLUSTER_JACOBI) { - *error = "CLUSTER_JACOBI preconditioner not suppored. Please build Ceres " - "with SuiteSparse support."; - return NULL; - } - - if (linear_solver_options.preconditioner_type == CLUSTER_TRIDIAGONAL) { - *error = "CLUSTER_TRIDIAGONAL preconditioner not suppored. Please build " - "Ceres with SuiteSparse support."; - return NULL; - } -#endif linear_solver_options.num_threads = options->num_linear_solver_threads; - linear_solver_options.num_eliminate_blocks = - options->num_eliminate_blocks; - - if ((linear_solver_options.num_eliminate_blocks == 0) && - IsSchurType(linear_solver_options.type)) { -#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE) - LOG(INFO) << "No elimination block remaining switching to DENSE_QR."; - linear_solver_options.type = DENSE_QR; -#else - LOG(INFO) << "No elimination block remaining " - << "switching to SPARSE_NORMAL_CHOLESKY."; - linear_solver_options.type = SPARSE_NORMAL_CHOLESKY; -#endif - } - -#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE) - if (linear_solver_options.type == SPARSE_SCHUR) { - *error = "Can't use SPARSE_SCHUR because neither SuiteSparse nor" - "CXSparse was enabled when Ceres was compiled."; - return NULL; - } -#endif - // The matrix used for storing the dense Schur complement has a // single lock guarding the whole matrix. Running the // SchurComplementSolver with multiple threads leads to maximum @@ -628,56 +1160,67 @@ LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options, << "switching to single-threaded."; linear_solver_options.num_threads = 1; } - - options->linear_solver_type = linear_solver_options.type; options->num_linear_solver_threads = linear_solver_options.num_threads; + linear_solver_options.use_block_amd = options->use_block_amd; + const map >& groups = + options->linear_solver_ordering->group_to_elements(); + for (map >::const_iterator it = groups.begin(); + it != groups.end(); + ++it) { + linear_solver_options.elimination_groups.push_back(it->second.size()); + } + // Schur type solvers, expect at least two elimination groups. If + // there is only one elimination group, then CreateReducedProgram + // guarantees that this group only contains e_blocks. Thus we add a + // dummy elimination group with zero blocks in it. + if (IsSchurType(linear_solver_options.type) && + linear_solver_options.elimination_groups.size() == 1) { + linear_solver_options.elimination_groups.push_back(0); + } + return LinearSolver::Create(linear_solver_options); } -bool SolverImpl::ApplyUserOrdering(const ProblemImpl& problem_impl, - vector& ordering, - Program* program, - string* error) { - if (ordering.size() != program->NumParameterBlocks()) { +bool SolverImpl::ApplyUserOrdering( + const ProblemImpl::ParameterMap& parameter_map, + const ParameterBlockOrdering* ordering, + Program* program, + string* error) { + if (ordering->NumElements() != program->NumParameterBlocks()) { *error = StringPrintf("User specified ordering does not have the same " "number of parameters as the problem. The problem" - "has %d blocks while the ordering has %ld blocks.", + "has %d blocks while the ordering has %d blocks.", program->NumParameterBlocks(), - ordering.size()); + ordering->NumElements()); return false; } - // Ensure that there are no duplicates in the user's ordering. - { - vector ordering_copy(ordering); - sort(ordering_copy.begin(), ordering_copy.end()); - if (unique(ordering_copy.begin(), ordering_copy.end()) - != ordering_copy.end()) { - *error = "User specified ordering contains duplicates."; - return false; - } - } - vector* parameter_blocks = program->mutable_parameter_blocks(); - - fill(parameter_blocks->begin(), - parameter_blocks->end(), - static_cast(NULL)); - - const ProblemImpl::ParameterMap& parameter_map = problem_impl.parameter_map(); - for (int i = 0; i < ordering.size(); ++i) { - ProblemImpl::ParameterMap::const_iterator it = - parameter_map.find(ordering[i]); - if (it == parameter_map.end()) { - *error = StringPrintf("User specified ordering contains a pointer " - "to a double that is not a parameter block in the " - "problem. The invalid double is at position %d " - " in options.ordering.", i); - return false; + parameter_blocks->clear(); + + const map >& groups = + ordering->group_to_elements(); + + for (map >::const_iterator group_it = groups.begin(); + group_it != groups.end(); + ++group_it) { + const set& group = group_it->second; + for (set::const_iterator parameter_block_ptr_it = group.begin(); + parameter_block_ptr_it != group.end(); + ++parameter_block_ptr_it) { + ProblemImpl::ParameterMap::const_iterator parameter_block_it = + parameter_map.find(*parameter_block_ptr_it); + if (parameter_block_it == parameter_map.end()) { + *error = StringPrintf("User specified ordering contains a pointer " + "to a double that is not a parameter block in " + "the problem. The invalid double is in group: %d", + group_it->first); + return false; + } + parameter_blocks->push_back(parameter_block_it->second); } - (*parameter_blocks)[i] = it->second; } return true; } @@ -704,36 +1247,31 @@ static int MinParameterBlock(const ResidualBlock* residual_block, // Reorder the residuals for program, if necessary, so that the residuals // involving each E block occur together. This is a necessary condition for the // Schur eliminator, which works on these "row blocks" in the jacobian. -bool SolverImpl::MaybeReorderResidualBlocks(const Solver::Options& options, - Program* program, - string* error) { - // Only Schur types require the lexicographic reordering. - if (!IsSchurType(options.linear_solver_type)) { - return true; - } - - CHECK_NE(0, options.num_eliminate_blocks) - << "Congratulations, you found a Ceres bug! Please report this error " - << "to the developers."; +bool SolverImpl::LexicographicallyOrderResidualBlocks( + const int num_eliminate_blocks, + Program* program, + string* error) { + CHECK_GE(num_eliminate_blocks, 1) + << "Congratulations, you found a Ceres bug! Please report this error " + << "to the developers."; // Create a histogram of the number of residuals for each E block. There is an // extra bucket at the end to catch all non-eliminated F blocks. - vector residual_blocks_per_e_block(options.num_eliminate_blocks + 1); + vector residual_blocks_per_e_block(num_eliminate_blocks + 1); vector* residual_blocks = program->mutable_residual_blocks(); vector min_position_per_residual(residual_blocks->size()); for (int i = 0; i < residual_blocks->size(); ++i) { ResidualBlock* residual_block = (*residual_blocks)[i]; - int position = MinParameterBlock(residual_block, - options.num_eliminate_blocks); + int position = MinParameterBlock(residual_block, num_eliminate_blocks); min_position_per_residual[i] = position; - DCHECK_LE(position, options.num_eliminate_blocks); + DCHECK_LE(position, num_eliminate_blocks); residual_blocks_per_e_block[position]++; } // Run a cumulative sum on the histogram, to obtain offsets to the start of // each histogram bucket (where each bucket is for the residuals for that // E-block). - vector offsets(options.num_eliminate_blocks + 1); + vector offsets(num_eliminate_blocks + 1); std::partial_sum(residual_blocks_per_e_block.begin(), residual_blocks_per_e_block.end(), offsets.begin()); @@ -772,7 +1310,7 @@ bool SolverImpl::MaybeReorderResidualBlocks(const Solver::Options& options, // Sanity check #1: The difference in bucket offsets should match the // histogram sizes. - for (int i = 0; i < options.num_eliminate_blocks; ++i) { + for (int i = 0; i < num_eliminate_blocks; ++i) { CHECK_EQ(residual_blocks_per_e_block[i], offsets[i + 1] - offsets[i]) << "Congratulations, you found a Ceres bug! Please report this error " << "to the developers."; @@ -789,15 +1327,76 @@ bool SolverImpl::MaybeReorderResidualBlocks(const Solver::Options& options, return true; } -Evaluator* SolverImpl::CreateEvaluator(const Solver::Options& options, - Program* program, - string* error) { +Evaluator* SolverImpl::CreateEvaluator( + const Solver::Options& options, + const ProblemImpl::ParameterMap& parameter_map, + Program* program, + string* error) { Evaluator::Options evaluator_options; evaluator_options.linear_solver_type = options.linear_solver_type; - evaluator_options.num_eliminate_blocks = options.num_eliminate_blocks; + evaluator_options.num_eliminate_blocks = + (options.linear_solver_ordering->NumGroups() > 0 && + IsSchurType(options.linear_solver_type)) + ? (options.linear_solver_ordering + ->group_to_elements().begin() + ->second.size()) + : 0; evaluator_options.num_threads = options.num_threads; return Evaluator::Create(evaluator_options, program, error); } +CoordinateDescentMinimizer* SolverImpl::CreateInnerIterationMinimizer( + const Solver::Options& options, + const Program& program, + const ProblemImpl::ParameterMap& parameter_map, + Solver::Summary* summary) { + scoped_ptr inner_iteration_minimizer( + new CoordinateDescentMinimizer); + scoped_ptr inner_iteration_ordering; + ParameterBlockOrdering* ordering_ptr = NULL; + + if (options.inner_iteration_ordering == NULL) { + // Find a recursive decomposition of the Hessian matrix as a set + // of independent sets of decreasing size and invert it. This + // seems to work better in practice, i.e., Cameras before + // points. + inner_iteration_ordering.reset(new ParameterBlockOrdering); + ComputeRecursiveIndependentSetOrdering(program, + inner_iteration_ordering.get()); + inner_iteration_ordering->Reverse(); + ordering_ptr = inner_iteration_ordering.get(); + } else { + const map >& group_to_elements = + options.inner_iteration_ordering->group_to_elements(); + + // Iterate over each group and verify that it is an independent + // set. + map >::const_iterator it = group_to_elements.begin(); + for ( ; it != group_to_elements.end(); ++it) { + if (!IsParameterBlockSetIndependent(it->second, + program.residual_blocks())) { + summary->error = + StringPrintf("The user-provided " + "parameter_blocks_for_inner_iterations does not " + "form an independent set. Group Id: %d", it->first); + return NULL; + } + } + ordering_ptr = options.inner_iteration_ordering; + } + + if (!inner_iteration_minimizer->Init(program, + parameter_map, + *ordering_ptr, + &summary->error)) { + return NULL; + } + + summary->inner_iterations = true; + SummarizeOrdering(ordering_ptr, &(summary->inner_iteration_ordering_used)); + + return inner_iteration_minimizer.release(); +} + } // namespace internal } // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/solver_impl.h b/extern/libmv/third_party/ceres/internal/ceres/solver_impl.h index 11b44de6f42..c5f5efad3d7 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/solver_impl.h +++ b/extern/libmv/third_party/ceres/internal/ceres/solver_impl.h @@ -31,17 +31,20 @@ #ifndef CERES_INTERNAL_SOLVER_IMPL_H_ #define CERES_INTERNAL_SOLVER_IMPL_H_ +#include #include #include #include "ceres/internal/port.h" +#include "ceres/ordered_groups.h" +#include "ceres/problem_impl.h" #include "ceres/solver.h" namespace ceres { namespace internal { +class CoordinateDescentMinimizer; class Evaluator; class LinearSolver; -class ProblemImpl; class Program; class SolverImpl { @@ -52,10 +55,19 @@ class SolverImpl { ProblemImpl* problem_impl, Solver::Summary* summary); + static void TrustRegionSolve(const Solver::Options& options, + ProblemImpl* problem_impl, + Solver::Summary* summary); + + static void LineSearchSolve(const Solver::Options& options, + ProblemImpl* problem_impl, + Solver::Summary* summary); + // Create the transformed Program, which has all the fixed blocks // and residuals eliminated, and in the case of automatic schur // ordering, has the E blocks first in the resulting program, with // options.num_eliminate_blocks set appropriately. + // // If fixed_cost is not NULL, the residual blocks that are removed // are evaluated and the sum of their cost is returned in fixed_cost. static Program* CreateReducedProgram(Solver::Options* options, @@ -71,46 +83,73 @@ class SolverImpl { static LinearSolver* CreateLinearSolver(Solver::Options* options, string* error); - // Reorder the parameter blocks in program using the vector - // ordering. A return value of true indicates success and false - // indicates an error was encountered whose cause is logged to - // LOG(ERROR). - static bool ApplyUserOrdering(const ProblemImpl& problem_impl, - vector& ordering, + // Reorder the parameter blocks in program using the ordering. A + // return value of true indicates success and false indicates an + // error was encountered whose cause is logged to LOG(ERROR). + static bool ApplyUserOrdering(const ProblemImpl::ParameterMap& parameter_map, + const ParameterBlockOrdering* ordering, Program* program, string* error); + // Reorder the residuals for program, if necessary, so that the - // residuals involving each E block occur together. This is a - // necessary condition for the Schur eliminator, which works on - // these "row blocks" in the jacobian. - static bool MaybeReorderResidualBlocks(const Solver::Options& options, - Program* program, - string* error); + // residuals involving e block (i.e., the first num_eliminate_block + // parameter blocks) occur together. This is a necessary condition + // for the Schur eliminator. + static bool LexicographicallyOrderResidualBlocks( + const int num_eliminate_blocks, + Program* program, + string* error); // Create the appropriate evaluator for the transformed program. - static Evaluator* CreateEvaluator(const Solver::Options& options, - Program* program, - string* error); - - // Run the minimization for the given evaluator and configuration. - static void Minimize(const Solver::Options &options, - Program* program, - Evaluator* evaluator, - LinearSolver* linear_solver, - double* parameters, - Solver::Summary* summary); + static Evaluator* CreateEvaluator( + const Solver::Options& options, + const ProblemImpl::ParameterMap& parameter_map, + Program* program, + string* error); + + // Run the TrustRegionMinimizer for the given evaluator and configuration. + static void TrustRegionMinimize( + const Solver::Options &options, + Program* program, + CoordinateDescentMinimizer* inner_iteration_minimizer, + Evaluator* evaluator, + LinearSolver* linear_solver, + double* parameters, + Solver::Summary* summary); + + // Run the LineSearchMinimizer for the given evaluator and configuration. + static void LineSearchMinimize( + const Solver::Options &options, + Program* program, + Evaluator* evaluator, + double* parameters, + Solver::Summary* summary); // Remove the fixed or unused parameter blocks and residuals // depending only on fixed parameters from the problem. Also updates // num_eliminate_blocks, since removed parameters changes the point - // at which the eliminated blocks is valid. - // If fixed_cost is not NULL, the residual blocks that are removed - // are evaluated and the sum of their cost is returned in fixed_cost. + // at which the eliminated blocks is valid. If fixed_cost is not + // NULL, the residual blocks that are removed are evaluated and the + // sum of their cost is returned in fixed_cost. static bool RemoveFixedBlocksFromProgram(Program* program, - int* num_eliminate_blocks, + ParameterBlockOrdering* ordering, double* fixed_cost, string* error); + + static bool IsOrderingValid(const Solver::Options& options, + const ProblemImpl* problem_impl, + string* error); + + static bool IsParameterBlockSetIndependent( + const set& parameter_block_ptrs, + const vector& residual_blocks); + + static CoordinateDescentMinimizer* CreateInnerIterationMinimizer( + const Solver::Options& options, + const Program& program, + const ProblemImpl::ParameterMap& parameter_map, + Solver::Summary* summary); }; } // namespace internal diff --git a/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc index 9e00b4402dc..dd05f0c6f41 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc @@ -39,12 +39,13 @@ #endif #include "ceres/compressed_row_sparse_matrix.h" +#include "ceres/internal/eigen.h" +#include "ceres/internal/scoped_ptr.h" #include "ceres/linear_solver.h" #include "ceres/suitesparse.h" #include "ceres/triplet_sparse_matrix.h" -#include "ceres/internal/eigen.h" -#include "ceres/internal/scoped_ptr.h" #include "ceres/types.h" +#include "ceres/wall_time.h" namespace ceres { namespace internal { @@ -103,6 +104,8 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingCXSparse( const double* b, const LinearSolver::PerSolveOptions& per_solve_options, double * x) { + EventLogger event_logger("SparseNormalCholeskySolver::CXSparse::Solve"); + LinearSolver::Summary summary; summary.num_iterations = 1; const int num_cols = A->num_cols(); @@ -129,25 +132,34 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingCXSparse( // off of Jt to compute the Cholesky factorization of the normal // equations. cs_di* A2 = cs_transpose(&At, 1); - cs_di* AtA = cs_multiply(&At,A2); + cs_di* AtA = cs_multiply(&At, A2); cxsparse_.Free(A2); if (per_solve_options.D != NULL) { A->DeleteRows(num_cols); } + event_logger.AddEvent("Setup"); + // Compute symbolic factorization if not available. if (cxsparse_factor_ == NULL) { cxsparse_factor_ = CHECK_NOTNULL(cxsparse_.AnalyzeCholesky(AtA)); } + event_logger.AddEvent("Analysis"); + + // Solve the linear system. if (cxsparse_.SolveCholesky(AtA, cxsparse_factor_, Atb.data())) { VectorRef(x, Atb.rows()) = Atb; summary.termination_type = TOLERANCE; } + event_logger.AddEvent("Solve"); + cxsparse_.Free(AtA); + + event_logger.AddEvent("Teardown"); return summary; } #else @@ -169,9 +181,9 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse( const double* b, const LinearSolver::PerSolveOptions& per_solve_options, double * x) { - const time_t start_time = time(NULL); - const int num_cols = A->num_cols(); + EventLogger event_logger("SparseNormalCholeskySolver::SuiteSparse::Solve"); + const int num_cols = A->num_cols(); LinearSolver::Summary summary; Vector Atb = Vector::Zero(num_cols); A->LeftMultiply(b, Atb.data()); @@ -189,7 +201,7 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse( CHECK_NOTNULL(lhs.get()); cholmod_dense* rhs = ss_.CreateDenseVector(Atb.data(), num_cols, num_cols); - const time_t init_time = time(NULL); + event_logger.AddEvent("Setup"); if (factor_ == NULL) { if (options_.use_block_amd) { @@ -206,11 +218,10 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse( } CHECK_NOTNULL(factor_); - - const time_t symbolic_time = time(NULL); + event_logger.AddEvent("Analysis"); cholmod_dense* sol = ss_.SolveCholesky(lhs.get(), factor_, rhs); - const time_t solve_time = time(NULL); + event_logger.AddEvent("Solve"); ss_.Free(rhs); rhs = NULL; @@ -228,12 +239,7 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse( summary.termination_type = TOLERANCE; } - const time_t cleanup_time = time(NULL); - VLOG(2) << "time (sec) total: " << (cleanup_time - start_time) - << " init: " << (init_time - start_time) - << " symbolic: " << (symbolic_time - init_time) - << " solve: " << (solve_time - symbolic_time) - << " cleanup: " << (cleanup_time - solve_time); + event_logger.AddEvent("Teardown"); return summary; } #else diff --git a/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h b/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h index 40d9e0a0327..8d48096d4c6 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h +++ b/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h @@ -35,8 +35,8 @@ #define CERES_INTERNAL_SPARSE_NORMAL_CHOLESKY_SOLVER_H_ #include "ceres/cxsparse.h" -#include "ceres/linear_solver.h" #include "ceres/internal/macros.h" +#include "ceres/linear_solver.h" #include "ceres/suitesparse.h" namespace ceres { diff --git a/extern/libmv/third_party/ceres/internal/ceres/split.cc b/extern/libmv/third_party/ceres/internal/ceres/split.cc index c65c8a5bb5d..3edbc281340 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/split.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/split.cc @@ -28,10 +28,11 @@ // // Author: keir@google.com (Keir Mierle) +#include "ceres/split.h" + #include #include #include -#include "ceres/split.h" #include "ceres/internal/port.h" namespace ceres { diff --git a/extern/libmv/third_party/ceres/internal/ceres/split.h b/extern/libmv/third_party/ceres/internal/ceres/split.h index ec579e974da..4df48c3a7cd 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/split.h +++ b/extern/libmv/third_party/ceres/internal/ceres/split.h @@ -2,7 +2,7 @@ // Author: keir@google.com (Keir Mierle) #ifndef CERES_INTERNAL_SPLIT_H_ -#define VISION_OPTIMIZATION_LEAST_SQUARES_INTERNAL_SPLIT_H_ +#define CERES_INTERNAL_SPLIT_H_ #include #include diff --git a/extern/libmv/third_party/ceres/internal/ceres/stl_util.h b/extern/libmv/third_party/ceres/internal/ceres/stl_util.h index a1a19e8b3ce..08f15ec8398 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/stl_util.h +++ b/extern/libmv/third_party/ceres/internal/ceres/stl_util.h @@ -31,6 +31,8 @@ #ifndef CERES_INTERNAL_STL_UTIL_H_ #define CERES_INTERNAL_STL_UTIL_H_ +#include + namespace ceres { // STLDeleteContainerPointers() @@ -53,6 +55,20 @@ void STLDeleteContainerPointers(ForwardIterator begin, } } +// Variant of STLDeleteContainerPointers which allows the container to +// contain duplicates. +template +void STLDeleteUniqueContainerPointers(ForwardIterator begin, + ForwardIterator end) { + sort(begin, end); + ForwardIterator new_end = unique(begin, end); + while (begin != new_end) { + ForwardIterator temp = begin; + ++begin; + delete *temp; + } +} + // STLDeleteElements() deletes all the elements in an STL container and clears // the container. This function is suitable for use with a vector, set, // hash_set, or any other STL container which defines sensible begin(), end(), diff --git a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc index 396a48b7d97..ce204674dce 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc @@ -28,13 +28,14 @@ // // Author: Sanjay Ghemawat +#include "ceres/stringprintf.h" + #include #include // For va_list and related operations #include // MSVC requires this for _vsnprintf #include #include -#include "ceres/stringprintf.h" #include "ceres/internal/port.h" namespace ceres { diff --git a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h index f2f907ab32d..cd1be142aed 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h +++ b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h @@ -65,17 +65,17 @@ namespace internal { // Return a C++ string. extern string StringPrintf(const char* format, ...) // Tell the compiler to do printf format string checking. - CERES_PRINTF_ATTRIBUTE(1,2); + CERES_PRINTF_ATTRIBUTE(1, 2); // Store result into a supplied string and return it. extern const string& SStringPrintf(string* dst, const char* format, ...) // Tell the compiler to do printf format string checking. - CERES_PRINTF_ATTRIBUTE(2,3); + CERES_PRINTF_ATTRIBUTE(2, 3); // Append result to a supplied string. extern void StringAppendF(string* dst, const char* format, ...) // Tell the compiler to do printf format string checking. - CERES_PRINTF_ATTRIBUTE(2,3); + CERES_PRINTF_ATTRIBUTE(2, 3); // Lower-level routine that takes a va_list and appends to a specified string. // All other routines are just convenience wrappers around it. diff --git a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc index cf3c48f84e6..d200aeb82f3 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc @@ -135,10 +135,11 @@ cholmod_factor* SuiteSparse::BlockAnalyzeCholesky( return AnalyzeCholeskyWithUserOrdering(A, ordering); } -cholmod_factor* SuiteSparse::AnalyzeCholeskyWithUserOrdering(cholmod_sparse* A, - const vector& ordering) { +cholmod_factor* SuiteSparse::AnalyzeCholeskyWithUserOrdering( + cholmod_sparse* A, + const vector& ordering) { CHECK_EQ(ordering.size(), A->nrow); - cc_.nmethods = 1 ; + cc_.nmethods = 1; cc_.method[0].ordering = CHOLMOD_GIVEN; cholmod_factor* factor = cholmod_analyze_p(A, const_cast(&ordering[0]), NULL, 0, &cc_); diff --git a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h index eb691c0c0ed..3fe79080d5d 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h +++ b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h @@ -39,9 +39,9 @@ #include #include -#include -#include "cholmod.h" #include "ceres/internal/port.h" +#include "cholmod.h" +#include "glog/logging.h" namespace ceres { namespace internal { diff --git a/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc index ed8677ea18a..a09f38ee24e 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc @@ -71,7 +71,8 @@ TripletSparseMatrix::TripletSparseMatrix(int num_rows, } TripletSparseMatrix::TripletSparseMatrix(const TripletSparseMatrix& orig) - : num_rows_(orig.num_rows_), + : SparseMatrix(), + num_rows_(orig.num_rows_), num_cols_(orig.num_cols_), max_num_nonzeros_(orig.max_num_nonzeros_), num_nonzeros_(orig.num_nonzeros_), diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc b/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc index 76c4f8a7580..981c60a12e7 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc @@ -45,8 +45,10 @@ #include "ceres/internal/scoped_ptr.h" #include "ceres/linear_least_squares_problems.h" #include "ceres/sparse_matrix.h" +#include "ceres/stringprintf.h" #include "ceres/trust_region_strategy.h" #include "ceres/types.h" +#include "ceres/wall_time.h" #include "glog/logging.h" namespace ceres { @@ -56,28 +58,13 @@ namespace { const double kEpsilon = 1e-12; } // namespace -// Execute the list of IterationCallbacks sequentially. If any one of -// the callbacks does not return SOLVER_CONTINUE, then stop and return -// its status. -CallbackReturnType TrustRegionMinimizer::RunCallbacks( - const IterationSummary& iteration_summary) { - for (int i = 0; i < options_.callbacks.size(); ++i) { - const CallbackReturnType status = - (*options_.callbacks[i])(iteration_summary); - if (status != SOLVER_CONTINUE) { - return status; - } - } - return SOLVER_CONTINUE; -} - // Compute a scaling vector that is used to improve the conditioning // of the Jacobian. void TrustRegionMinimizer::EstimateScale(const SparseMatrix& jacobian, double* scale) const { jacobian.SquaredColumnNorm(scale); for (int i = 0; i < jacobian.num_cols(); ++i) { - scale[i] = 1.0 / (kEpsilon + sqrt(scale[i])); + scale[i] = 1.0 / (1.0 + sqrt(scale[i])); } } @@ -96,29 +83,19 @@ bool TrustRegionMinimizer::MaybeDumpLinearLeastSquaresProblem( // moved inside TrustRegionStrategy, its not clear how we dump the // regularization vector/matrix anymore. // - // Doing this right requires either an API change to the - // TrustRegionStrategy and/or how LinearLeastSquares problems are - // stored on disk. + // Also num_eliminate_blocks is not visible to the trust region + // minimizer either. // - // For now, we will just not dump the regularizer. - return (!binary_search(options_.lsqp_iterations_to_dump.begin(), - options_.lsqp_iterations_to_dump.end(), - iteration) || - DumpLinearLeastSquaresProblem(options_.lsqp_dump_directory, - iteration, - options_.lsqp_dump_format_type, - jacobian, - NULL, - residuals, - step, - options_.num_eliminate_blocks)); + // Both of these indicate that this is the wrong place for this + // code, and going forward this should needs fixing/refactoring. + return true; } void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, double* parameters, Solver::Summary* summary) { - time_t start_time = time(NULL); - time_t iteration_start_time = start_time; + double start_time = WallTimeInSeconds(); + double iteration_start_time = start_time; Init(options); summary->termination_type = NO_CONVERGENCE; @@ -149,7 +126,6 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, iteration_summary.iteration = 0; iteration_summary.step_is_valid = false; iteration_summary.step_is_successful = false; - iteration_summary.cost = summary->initial_cost; iteration_summary.cost_change = 0.0; iteration_summary.gradient_max_norm = 0.0; iteration_summary.step_norm = 0.0; @@ -169,6 +145,9 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, return; } + summary->initial_cost = cost + summary->fixed_cost; + iteration_summary.cost = cost + summary->fixed_cost; + int num_consecutive_nonmonotonic_steps = 0; double minimum_cost = cost; double reference_cost = cost; @@ -189,45 +168,34 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, // The initial gradient max_norm is bounded from below so that we do // not divide by zero. - const double gradient_max_norm_0 = + const double initial_gradient_max_norm = max(iteration_summary.gradient_max_norm, kEpsilon); const double absolute_gradient_tolerance = - options_.gradient_tolerance * gradient_max_norm_0; + options_.gradient_tolerance * initial_gradient_max_norm; if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) { summary->termination_type = GRADIENT_TOLERANCE; VLOG(1) << "Terminating: Gradient tolerance reached." << "Relative gradient max norm: " - << iteration_summary.gradient_max_norm / gradient_max_norm_0 + << iteration_summary.gradient_max_norm / initial_gradient_max_norm << " <= " << options_.gradient_tolerance; return; } iteration_summary.iteration_time_in_seconds = - time(NULL) - iteration_start_time; - iteration_summary.cumulative_time_in_seconds = time(NULL) - start_time + - summary->preprocessor_time_in_seconds; + WallTimeInSeconds() - iteration_start_time; + iteration_summary.cumulative_time_in_seconds = + WallTimeInSeconds() - start_time + + summary->preprocessor_time_in_seconds; summary->iterations.push_back(iteration_summary); - // Call the various callbacks. - switch (RunCallbacks(iteration_summary)) { - case SOLVER_TERMINATE_SUCCESSFULLY: - summary->termination_type = USER_SUCCESS; - VLOG(1) << "Terminating: User callback returned USER_SUCCESS."; - return; - case SOLVER_ABORT: - summary->termination_type = USER_ABORT; - VLOG(1) << "Terminating: User callback returned USER_ABORT."; - return; - case SOLVER_CONTINUE: - break; - default: - LOG(FATAL) << "Unknown type of user callback status"; - } - int num_consecutive_invalid_steps = 0; while (true) { - iteration_start_time = time(NULL); + if (!RunCallbacks(options.callbacks, iteration_summary, summary)) { + return; + } + + iteration_start_time = WallTimeInSeconds(); if (iteration_summary.iteration >= options_.max_num_iterations) { summary->termination_type = NO_CONVERGENCE; VLOG(1) << "Terminating: Maximum number of iterations reached."; @@ -248,7 +216,7 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, iteration_summary.step_is_valid = false; iteration_summary.step_is_successful = false; - const time_t strategy_start_time = time(NULL); + const double strategy_start_time = WallTimeInSeconds(); TrustRegionStrategy::PerSolveOptions per_solve_options; per_solve_options.eta = options_.eta; TrustRegionStrategy::Summary strategy_summary = @@ -258,7 +226,7 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, trust_region_step.data()); iteration_summary.step_solver_time_in_seconds = - time(NULL) - strategy_start_time; + WallTimeInSeconds() - strategy_start_time; iteration_summary.linear_solver_iterations = strategy_summary.num_iterations; @@ -270,23 +238,24 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, << options.lsqp_dump_directory << "but failed."; } - double new_model_cost = 0.0; + double model_cost_change = 0.0; if (strategy_summary.termination_type != FAILURE) { - // new_model_cost = 1/2 |f + J * step|^2 - model_residuals = residuals; + // new_model_cost + // = 1/2 [f + J * step]^2 + // = 1/2 [ f'f + 2f'J * step + step' * J' * J * step ] + // model_cost_change + // = cost - new_model_cost + // = f'f/2 - 1/2 [ f'f + 2f'J * step + step' * J' * J * step] + // = -f'J * step - step' * J' * J * step / 2 + model_residuals.setZero(); jacobian->RightMultiply(trust_region_step.data(), model_residuals.data()); - new_model_cost = model_residuals.squaredNorm() / 2.0; - - // In exact arithmetic, this would never be the case. But poorly - // conditioned matrices can give rise to situations where the - // new_model_cost can actually be larger than half the squared - // norm of the residual vector. We allow for small tolerance - // around cost and beyond that declare the step to be invalid. - if ((1.0 - new_model_cost / cost) < -kEpsilon) { + model_cost_change = -(residuals.dot(model_residuals) + + model_residuals.squaredNorm() / 2.0); + + if (model_cost_change < 0.0) { VLOG(1) << "Invalid step: current_cost: " << cost - << " new_model_cost " << new_model_cost - << " absolute difference " << (cost - new_model_cost) - << " relative difference " << (1.0 - new_model_cost/cost); + << " absolute difference " << model_cost_change + << " relative difference " << (model_cost_change / cost); } else { iteration_summary.step_is_valid = true; } @@ -299,10 +268,12 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, if (++num_consecutive_invalid_steps >= options_.max_num_consecutive_invalid_steps) { summary->termination_type = NUMERICAL_FAILURE; - LOG(WARNING) << "Terminating. Number of successive invalid steps more " - << "than " - << "Solver::Options::max_num_consecutive_invalid_steps: " - << options_.max_num_consecutive_invalid_steps; + summary->error = StringPrintf( + "Terminating. Number of successive invalid steps more " + "than Solver::Options::max_num_consecutive_invalid_steps: %d", + options_.max_num_consecutive_invalid_steps); + + LOG(WARNING) << summary->error; return; } @@ -311,7 +282,7 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, // as an unsuccessful iteration. Since the various callbacks are // still executed, we are going to fill the iteration summary // with data that assumes a step of length zero and no progress. - iteration_summary.cost = cost; + iteration_summary.cost = cost + summary->fixed_cost; iteration_summary.cost_change = 0.0; iteration_summary.gradient_max_norm = summary->iterations.back().gradient_max_norm; @@ -322,51 +293,19 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, // The step is numerically valid, so now we can judge its quality. num_consecutive_invalid_steps = 0; - // We allow some slop around 0, and clamp the model_cost_change - // at kEpsilon * min(1.0, cost) from below. - // - // In exact arithmetic this should never be needed, as we are - // guaranteed to new_model_cost <= cost. However, due to various - // numerical issues, it is possible that new_model_cost is - // nearly equal to cost, and the difference is a small negative - // number. To make sure that the relative_decrease computation - // remains sane, as clamp the difference (cost - new_model_cost) - // from below at a small positive number. - // - // This number is the minimum of kEpsilon * (cost, 1.0), which - // ensures that it will never get too large in absolute value, - // while scaling down proportionally with the magnitude of the - // cost. This is important for problems where the minimum of the - // objective function is near zero. - const double model_cost_change = - max(kEpsilon * min(1.0, cost), cost - new_model_cost); - // Undo the Jacobian column scaling. delta = (trust_region_step.array() * scale.array()).matrix(); - iteration_summary.step_norm = delta.norm(); - - // Convergence based on parameter_tolerance. - const double step_size_tolerance = options_.parameter_tolerance * - (x_norm + options_.parameter_tolerance); - if (iteration_summary.step_norm <= step_size_tolerance) { - VLOG(1) << "Terminating. Parameter tolerance reached. " - << "relative step_norm: " - << iteration_summary.step_norm / - (x_norm + options_.parameter_tolerance) - << " <= " << options_.parameter_tolerance; - summary->termination_type = PARAMETER_TOLERANCE; - return; - } - if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) { summary->termination_type = NUMERICAL_FAILURE; - LOG(WARNING) << "Terminating. Failed to compute " - << "Plus(x, delta, x_plus_delta)."; + summary->error = + "Terminating. Failed to compute Plus(x, delta, x_plus_delta)."; + + LOG(WARNING) << summary->error; return; } // Try this step. - double new_cost; + double new_cost = numeric_limits::max(); if (!evaluator->Evaluate(x_plus_delta.data(), &new_cost, NULL, NULL, NULL)) { @@ -375,6 +314,45 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, LOG(WARNING) << "Step failed to evaluate. " << "Treating it as step with infinite cost"; new_cost = numeric_limits::max(); + } else { + // Check if performing an inner iteration will make it better. + if (options.inner_iteration_minimizer != NULL) { + const double x_plus_delta_cost = new_cost; + Vector inner_iteration_x = x_plus_delta; + Solver::Summary inner_iteration_summary; + options.inner_iteration_minimizer->Minimize(options, + inner_iteration_x.data(), + &inner_iteration_summary); + if (!evaluator->Evaluate(inner_iteration_x.data(), + &new_cost, + NULL, NULL, NULL)) { + VLOG(2) << "Inner iteration failed."; + new_cost = x_plus_delta_cost; + } else { + x_plus_delta = inner_iteration_x; + // Boost the model_cost_change, since the inner iteration + // improvements are not accounted for by the trust region. + model_cost_change += x_plus_delta_cost - new_cost; + VLOG(2) << "Inner iteration succeeded; current cost: " << cost + << " x_plus_delta_cost: " << x_plus_delta_cost + << " new_cost: " << new_cost; + } + } + } + + iteration_summary.step_norm = (x - x_plus_delta).norm(); + + // Convergence based on parameter_tolerance. + const double step_size_tolerance = options_.parameter_tolerance * + (x_norm + options_.parameter_tolerance); + if (iteration_summary.step_norm <= step_size_tolerance) { + VLOG(1) << "Terminating. Parameter tolerance reached. " + << "relative step_norm: " + << iteration_summary.step_norm / + (x_norm + options_.parameter_tolerance) + << " <= " << options_.parameter_tolerance; + summary->termination_type = PARAMETER_TOLERANCE; + return; } VLOG(2) << "old cost: " << cost << " new cost: " << new_cost; @@ -421,6 +399,7 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, accumulated_candidate_model_cost_change += model_cost_change; accumulated_reference_model_cost_change += model_cost_change; if (relative_decrease <= options_.min_relative_decrease) { + iteration_summary.step_is_nonmonotonic = true; VLOG(2) << "Non-monotonic step! " << " relative_decrease: " << relative_decrease << " historical_relative_decrease: " @@ -443,7 +422,9 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, NULL, jacobian)) { summary->termination_type = NUMERICAL_FAILURE; - LOG(WARNING) << "Terminating: Residual and Jacobian evaluation failed."; + summary->error = + "Terminating: Residual and Jacobian evaluation failed."; + LOG(WARNING) << summary->error; return; } @@ -455,7 +436,8 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, summary->termination_type = GRADIENT_TOLERANCE; VLOG(1) << "Terminating: Gradient tolerance reached." << "Relative gradient max norm: " - << iteration_summary.gradient_max_norm / gradient_max_norm_0 + << (iteration_summary.gradient_max_norm / + initial_gradient_max_norm) << " <= " << options_.gradient_tolerance; return; } @@ -523,25 +505,11 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, } iteration_summary.iteration_time_in_seconds = - time(NULL) - iteration_start_time; - iteration_summary.cumulative_time_in_seconds = time(NULL) - start_time + - summary->preprocessor_time_in_seconds; + WallTimeInSeconds() - iteration_start_time; + iteration_summary.cumulative_time_in_seconds = + WallTimeInSeconds() - start_time + + summary->preprocessor_time_in_seconds; summary->iterations.push_back(iteration_summary); - - switch (RunCallbacks(iteration_summary)) { - case SOLVER_TERMINATE_SUCCESSFULLY: - summary->termination_type = USER_SUCCESS; - VLOG(1) << "Terminating: User callback returned USER_SUCCESS."; - return; - case SOLVER_ABORT: - summary->termination_type = USER_ABORT; - VLOG(1) << "Terminating: User callback returned USER_ABORT."; - return; - case SOLVER_CONTINUE: - break; - default: - LOG(FATAL) << "Unknown type of user callback status"; - } } } diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h b/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h index a4f5ba3674d..9a022843233 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h +++ b/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h @@ -39,8 +39,7 @@ namespace ceres { namespace internal { // Generic trust region minimization algorithm. The heavy lifting is -// done by a TrustRegionStrategy object passed in as one of the -// arguments to the Minimize method. +// done by a TrustRegionStrategy object passed in as part of options. // // For example usage, see SolverImpl::Minimize. class TrustRegionMinimizer : public Minimizer { @@ -53,11 +52,10 @@ class TrustRegionMinimizer : public Minimizer { private: void Init(const Minimizer::Options& options); void EstimateScale(const SparseMatrix& jacobian, double* scale) const; - CallbackReturnType RunCallbacks(const IterationSummary& iteration_summary); - bool MaybeDumpLinearLeastSquaresProblem( const int iteration, - const SparseMatrix* jacobian, - const double* residuals, - const double* step) const; + bool MaybeDumpLinearLeastSquaresProblem(const int iteration, + const SparseMatrix* jacobian, + const double* residuals, + const double* step) const; Minimizer::Options options_; }; diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc b/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc index 89bc19d084b..c68269d0449 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc @@ -1,3 +1,35 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012, 2013 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// +// Author: sameeragarwal@google.com (Sameer Agarwal) +// keir@google.com (Keir Mierle) + #include "ceres/trust_region_strategy.h" #include "ceres/dogleg_strategy.h" #include "ceres/levenberg_marquardt_strategy.h" diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h b/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h index 391da97d5eb..f150594bbd2 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h +++ b/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h @@ -52,7 +52,7 @@ class SparseMatrix; // radius to scale the damping term, which controls the step size, but // does not set a hard limit on its size. class TrustRegionStrategy { -public: + public: struct Options { Options() : trust_region_strategy_type(LEVENBERG_MARQUARDT), diff --git a/extern/libmv/third_party/ceres/internal/ceres/types.cc b/extern/libmv/third_party/ceres/internal/ceres/types.cc index 05e573ff6d5..2e19322cc76 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/types.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/types.cc @@ -28,15 +28,23 @@ // // Author: sameeragarwal@google.com (Sameer Agarwal) +#include +#include #include #include "ceres/types.h" +#include "glog/logging.h" namespace ceres { #define CASESTR(x) case x: return #x +#define STRENUM(x) if (value == #x) { *type = x; return true;} -const char* LinearSolverTypeToString(LinearSolverType solver_type) { - switch (solver_type) { +static void UpperCase(string* input) { + std::transform(input->begin(), input->end(), input->begin(), ::toupper); +} + +const char* LinearSolverTypeToString(LinearSolverType type) { + switch (type) { CASESTR(DENSE_NORMAL_CHOLESKY); CASESTR(DENSE_QR); CASESTR(SPARSE_NORMAL_CHOLESKY); @@ -49,9 +57,20 @@ const char* LinearSolverTypeToString(LinearSolverType solver_type) { } } -const char* PreconditionerTypeToString( - PreconditionerType preconditioner_type) { - switch (preconditioner_type) { +bool StringToLinearSolverType(string value, LinearSolverType* type) { + UpperCase(&value); + STRENUM(DENSE_NORMAL_CHOLESKY); + STRENUM(DENSE_QR); + STRENUM(SPARSE_NORMAL_CHOLESKY); + STRENUM(DENSE_SCHUR); + STRENUM(SPARSE_SCHUR); + STRENUM(ITERATIVE_SCHUR); + STRENUM(CGNR); + return false; +} + +const char* PreconditionerTypeToString(PreconditionerType type) { + switch (type) { CASESTR(IDENTITY); CASESTR(JACOBI); CASESTR(SCHUR_JACOBI); @@ -62,9 +81,19 @@ const char* PreconditionerTypeToString( } } +bool StringToPreconditionerType(string value, PreconditionerType* type) { + UpperCase(&value); + STRENUM(IDENTITY); + STRENUM(JACOBI); + STRENUM(SCHUR_JACOBI); + STRENUM(CLUSTER_JACOBI); + STRENUM(CLUSTER_TRIDIAGONAL); + return false; +} + const char* SparseLinearAlgebraLibraryTypeToString( - SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type) { - switch (sparse_linear_algebra_library_type) { + SparseLinearAlgebraLibraryType type) { + switch (type) { CASESTR(SUITE_SPARSE); CASESTR(CX_SPARSE); default: @@ -72,19 +101,121 @@ const char* SparseLinearAlgebraLibraryTypeToString( } } -const char* OrderingTypeToString(OrderingType ordering_type) { - switch (ordering_type) { - CASESTR(NATURAL); - CASESTR(USER); - CASESTR(SCHUR); + +bool StringToSparseLinearAlgebraLibraryType( + string value, + SparseLinearAlgebraLibraryType* type) { + UpperCase(&value); + STRENUM(SUITE_SPARSE); + STRENUM(CX_SPARSE); + return false; +} + +const char* TrustRegionStrategyTypeToString(TrustRegionStrategyType type) { + switch (type) { + CASESTR(LEVENBERG_MARQUARDT); + CASESTR(DOGLEG); + default: + return "UNKNOWN"; + } +} + +bool StringToTrustRegionStrategyType(string value, + TrustRegionStrategyType* type) { + UpperCase(&value); + STRENUM(LEVENBERG_MARQUARDT); + STRENUM(DOGLEG); + return false; +} + +const char* DoglegTypeToString(DoglegType type) { + switch (type) { + CASESTR(TRADITIONAL_DOGLEG); + CASESTR(SUBSPACE_DOGLEG); + default: + return "UNKNOWN"; + } +} + +bool StringToDoglegType(string value, DoglegType* type) { + UpperCase(&value); + STRENUM(TRADITIONAL_DOGLEG); + STRENUM(SUBSPACE_DOGLEG); + return false; +} + +const char* MinimizerTypeToString(MinimizerType type) { + switch (type) { + CASESTR(TRUST_REGION); + CASESTR(LINE_SEARCH); + default: + return "UNKNOWN"; + } +} + +bool StringToMinimizerType(string value, MinimizerType* type) { + UpperCase(&value); + STRENUM(TRUST_REGION); + STRENUM(LINE_SEARCH); + return false; +} + +const char* LineSearchDirectionTypeToString(LineSearchDirectionType type) { + switch (type) { + CASESTR(STEEPEST_DESCENT); + CASESTR(NONLINEAR_CONJUGATE_GRADIENT); + CASESTR(LBFGS); + default: + return "UNKNOWN"; + } +} + +bool StringToLineSearchDirectionType(string value, + LineSearchDirectionType* type) { + UpperCase(&value); + STRENUM(STEEPEST_DESCENT); + STRENUM(NONLINEAR_CONJUGATE_GRADIENT); + STRENUM(LBFGS); + return false; +} + +const char* LineSearchTypeToString(LineSearchType type) { + switch (type) { + CASESTR(ARMIJO); default: return "UNKNOWN"; } } -const char* SolverTerminationTypeToString( - SolverTerminationType termination_type) { - switch (termination_type) { +bool StringToLineSearchType(string value, LineSearchType* type) { + UpperCase(&value); + STRENUM(ARMIJO); + return false; +} + +const char* NonlinearConjugateGradientTypeToString( + NonlinearConjugateGradientType type) { + switch (type) { + CASESTR(FLETCHER_REEVES); + CASESTR(POLAK_RIBIRERE); + CASESTR(HESTENES_STIEFEL); + default: + return "UNKNOWN"; + } +} + +bool StringToNonlinearConjugateGradientType( + string value, + NonlinearConjugateGradientType* type) { + UpperCase(&value); + STRENUM(FLETCHER_REEVES); + STRENUM(POLAK_RIBIRERE); + STRENUM(HESTENES_STIEFEL); + return false; +} + +const char* SolverTerminationTypeToString(SolverTerminationType type) { + switch (type) { CASESTR(NO_CONVERGENCE); CASESTR(FUNCTION_TOLERANCE); CASESTR(GRADIENT_TOLERANCE); @@ -98,29 +229,20 @@ const char* SolverTerminationTypeToString( } } -#if 0 /* UNUSED */ -static const char* SparseLinearAlgebraTypeToString( - SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type) { - switch (sparse_linear_algebra_library_type) { - CASESTR(CX_SPARSE); - CASESTR(SUITE_SPARSE); - default: - return "UNKNOWN"; - } -} -#endif - -const char* TrustRegionStrategyTypeToString( - TrustRegionStrategyType trust_region_strategy_type) { - switch (trust_region_strategy_type) { - CASESTR(LEVENBERG_MARQUARDT); - CASESTR(DOGLEG); +const char* LinearSolverTerminationTypeToString( + LinearSolverTerminationType type) { + switch (type) { + CASESTR(TOLERANCE); + CASESTR(MAX_ITERATIONS); + CASESTR(STAGNATION); + CASESTR(FAILURE); default: return "UNKNOWN"; } } #undef CASESTR +#undef STRENUM bool IsSchurType(LinearSolverType type) { return ((type == SPARSE_SCHUR) || @@ -128,4 +250,26 @@ bool IsSchurType(LinearSolverType type) { (type == ITERATIVE_SCHUR)); } +bool IsSparseLinearAlgebraLibraryTypeAvailable( + SparseLinearAlgebraLibraryType type) { + if (type == SUITE_SPARSE) { +#ifdef CERES_NO_SUITESPARSE + return false; +#else + return true; +#endif + } + + if (type == CX_SPARSE) { +#ifdef CERES_NO_CXSPARSE + return false; +#else + return true; +#endif + } + + LOG(WARNING) << "Unknown sparse linear algebra library " << type; + return false; +} + } // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility.cc b/extern/libmv/third_party/ceres/internal/ceres/visibility.cc index 564cc54493e..8e80fd121bb 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/visibility.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/visibility.cc @@ -28,6 +28,8 @@ // // Author: kushalav@google.com (Avanish Kushal) +#include "ceres/visibility.h" + #include #include #include @@ -36,7 +38,6 @@ #include #include "ceres/block_structure.h" #include "ceres/collections_port.h" -#include "ceres/visibility.h" #include "ceres/graph.h" #include "glog/logging.h" diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility.h b/extern/libmv/third_party/ceres/internal/ceres/visibility.h index 692dd87201e..f29e3c6a0a8 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/visibility.h +++ b/extern/libmv/third_party/ceres/internal/ceres/visibility.h @@ -42,7 +42,7 @@ namespace ceres { namespace internal { -class CompressedRowBlockStructure; +struct CompressedRowBlockStructure; // Given a compressed row block structure, computes the set of // e_blocks "visible" to each f_block. If an e_block co-occurs with an diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc b/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc index 4caad03d7a1..a75d6f0c17e 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc +++ b/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc @@ -65,17 +65,17 @@ static const double kSimilarityPenaltyWeight = 0.0; #ifndef CERES_NO_SUITESPARSE VisibilityBasedPreconditioner::VisibilityBasedPreconditioner( const CompressedRowBlockStructure& bs, - const LinearSolver::Options& options) + const Preconditioner::Options& options) : options_(options), num_blocks_(0), num_clusters_(0), factor_(NULL) { - CHECK_GT(options_.num_eliminate_blocks, 0); - CHECK(options_.preconditioner_type == SCHUR_JACOBI || - options_.preconditioner_type == CLUSTER_JACOBI || - options_.preconditioner_type == CLUSTER_TRIDIAGONAL) - << "Unknown preconditioner type: " << options_.preconditioner_type; - num_blocks_ = bs.cols.size() - options_.num_eliminate_blocks; + CHECK_GT(options_.elimination_groups.size(), 1); + CHECK_GT(options_.elimination_groups[0], 0); + CHECK(options_.type == CLUSTER_JACOBI || + options_.type == CLUSTER_TRIDIAGONAL) + << "Unknown preconditioner type: " << options_.type; + num_blocks_ = bs.cols.size() - options_.elimination_groups[0]; CHECK_GT(num_blocks_, 0) << "Jacobian should have atleast 1 f_block for " << "visibility based preconditioning."; @@ -83,14 +83,11 @@ VisibilityBasedPreconditioner::VisibilityBasedPreconditioner( // Vector of camera block sizes block_size_.resize(num_blocks_); for (int i = 0; i < num_blocks_; ++i) { - block_size_[i] = bs.cols[i + options_.num_eliminate_blocks].size; + block_size_[i] = bs.cols[i + options_.elimination_groups[0]].size; } const time_t start_time = time(NULL); - switch (options_.preconditioner_type) { - case SCHUR_JACOBI: - ComputeSchurJacobiSparsity(bs); - break; + switch (options_.type) { case CLUSTER_JACOBI: ComputeClusterJacobiSparsity(bs); break; @@ -130,24 +127,6 @@ VisibilityBasedPreconditioner::~VisibilityBasedPreconditioner() { } } -// Determine the sparsity structure of the SCHUR_JACOBI -// preconditioner. SCHUR_JACOBI is an extreme case of a visibility -// based preconditioner where each camera block corresponds to a -// cluster and there is no interaction between clusters. -void VisibilityBasedPreconditioner::ComputeSchurJacobiSparsity( - const CompressedRowBlockStructure& bs) { - num_clusters_ = num_blocks_; - cluster_membership_.resize(num_blocks_); - cluster_pairs_.clear(); - - // Each camea block is a member of its own cluster and the only - // cluster pairs are the self edges (i,i). - for (int i = 0; i < num_clusters_; ++i) { - cluster_membership_[i] = i; - cluster_pairs_.insert(make_pair(i, i)); - } -} - // Determine the sparsity structure of the CLUSTER_JACOBI // preconditioner. It clusters cameras using their scene // visibility. The clusters form the diagonal blocks of the @@ -155,7 +134,7 @@ void VisibilityBasedPreconditioner::ComputeSchurJacobiSparsity( void VisibilityBasedPreconditioner::ComputeClusterJacobiSparsity( const CompressedRowBlockStructure& bs) { vector > visibility; - ComputeVisibility(bs, options_.num_eliminate_blocks, &visibility); + ComputeVisibility(bs, options_.elimination_groups[0], &visibility); CHECK_EQ(num_blocks_, visibility.size()); ClusterCameras(visibility); cluster_pairs_.clear(); @@ -173,7 +152,7 @@ void VisibilityBasedPreconditioner::ComputeClusterJacobiSparsity( void VisibilityBasedPreconditioner::ComputeClusterTridiagonalSparsity( const CompressedRowBlockStructure& bs) { vector > visibility; - ComputeVisibility(bs, options_.num_eliminate_blocks, &visibility); + ComputeVisibility(bs, options_.elimination_groups[0], &visibility); CHECK_EQ(num_blocks_, visibility.size()); ClusterCameras(visibility); @@ -253,7 +232,7 @@ void VisibilityBasedPreconditioner::ComputeBlockPairsInPreconditioner( int r = 0; const int num_row_blocks = bs.rows.size(); - const int num_eliminate_blocks = options_.num_eliminate_blocks; + const int num_eliminate_blocks = options_.elimination_groups[0]; // Iterate over each row of the matrix. The block structure of the // matrix is assumed to be sorted in order of the e_blocks/point @@ -331,16 +310,16 @@ void VisibilityBasedPreconditioner::ComputeBlockPairsInPreconditioner( void VisibilityBasedPreconditioner::InitEliminator( const CompressedRowBlockStructure& bs) { LinearSolver::Options eliminator_options; - eliminator_options.num_eliminate_blocks = options_.num_eliminate_blocks; + eliminator_options.elimination_groups = options_.elimination_groups; eliminator_options.num_threads = options_.num_threads; - DetectStructure(bs, options_.num_eliminate_blocks, + DetectStructure(bs, options_.elimination_groups[0], &eliminator_options.row_block_size, &eliminator_options.e_block_size, &eliminator_options.f_block_size); eliminator_.reset(SchurEliminatorBase::Create(eliminator_options)); - eliminator_->Init(options_.num_eliminate_blocks, &bs); + eliminator_->Init(options_.elimination_groups[0], &bs); } // Update the values of the preconditioner matrix and factorize it. @@ -364,13 +343,13 @@ bool VisibilityBasedPreconditioner::Update(const BlockSparseMatrixBase& A, // Compute a subset of the entries of the Schur complement. eliminator_->Eliminate(&A, b.data(), D, m_.get(), rhs.data()); - // Try factorizing the matrix. For SCHUR_JACOBI and CLUSTER_JACOBI, - // this should always succeed modulo some numerical/conditioning - // problems. For CLUSTER_TRIDIAGONAL, in general the preconditioner - // matrix as constructed is not positive definite. However, we will - // go ahead and try factorizing it. If it works, great, otherwise we - // scale all the cells in the preconditioner corresponding to the - // edges in the degree-2 forest and that guarantees positive + // Try factorizing the matrix. For CLUSTER_JACOBI, this should + // always succeed modulo some numerical/conditioning problems. For + // CLUSTER_TRIDIAGONAL, in general the preconditioner matrix as + // constructed is not positive definite. However, we will go ahead + // and try factorizing it. If it works, great, otherwise we scale + // all the cells in the preconditioner corresponding to the edges in + // the degree-2 forest and that guarantees positive // definiteness. The proof of this fact can be found in Lemma 1 in // "Visibility Based Preconditioning for Bundle Adjustment". // @@ -380,10 +359,10 @@ bool VisibilityBasedPreconditioner::Update(const BlockSparseMatrixBase& A, // The scaling only affects the tri-diagonal case, since // ScaleOffDiagonalBlocks only pays attenion to the cells that - // belong to the edges of the degree-2 forest. In the SCHUR_JACOBI - // and the CLUSTER_JACOBI cases, the preconditioner is guaranteed to - // be positive semidefinite. - if (!status && options_.preconditioner_type == CLUSTER_TRIDIAGONAL) { + // belong to the edges of the degree-2 forest. In the CLUSTER_JACOBI + // case, the preconditioner is guaranteed to be positive + // semidefinite. + if (!status && options_.type == CLUSTER_TRIDIAGONAL) { VLOG(1) << "Unscaled factorization failed. Retrying with off-diagonal " << "scaling"; ScaleOffDiagonalCells(); diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h b/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h index 888c65eba3a..8a09c78d36a 100644 --- a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h +++ b/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h @@ -29,25 +29,19 @@ // Author: sameeragarwal@google.com (Sameer Agarwal) // // Preconditioners for linear systems that arise in Structure from -// Motion problems. VisibilityBasedPreconditioner implements three -// preconditioners: +// Motion problems. VisibilityBasedPreconditioner implements: // -// SCHUR_JACOBI // CLUSTER_JACOBI // CLUSTER_TRIDIAGONAL // // Detailed descriptions of these preconditions beyond what is // documented here can be found in // -// Bundle Adjustment in the Large -// S. Agarwal, N. Snavely, S. Seitz & R. Szeliski, ECCV 2010 -// http://www.cs.washington.edu/homes/sagarwal/bal.pdf -// // Visibility Based Preconditioning for Bundle Adjustment // A. Kushal & S. Agarwal, submitted to CVPR 2012 // http://www.cs.washington.edu/homes/sagarwal/vbp.pdf // -// The three preconditioners share enough code that its most efficient +// The two preconditioners share enough code that its most efficient // to implement them as part of the same code base. #ifndef CERES_INTERNAL_VISIBILITY_BASED_PRECONDITIONER_H_ @@ -58,36 +52,26 @@ #include #include "ceres/collections_port.h" #include "ceres/graph.h" -#include "ceres/linear_solver.h" -#include "ceres/linear_operator.h" -#include "ceres/suitesparse.h" #include "ceres/internal/macros.h" #include "ceres/internal/scoped_ptr.h" +#include "ceres/preconditioner.h" +#include "ceres/suitesparse.h" namespace ceres { namespace internal { class BlockRandomAccessSparseMatrix; class BlockSparseMatrixBase; -class CompressedRowBlockStructure; +struct CompressedRowBlockStructure; class SchurEliminatorBase; -// This class implements three preconditioners for Structure from -// Motion/Bundle Adjustment problems. The name +// This class implements visibility based preconditioners for +// Structure from Motion/Bundle Adjustment problems. The name // VisibilityBasedPreconditioner comes from the fact that the sparsity // structure of the preconditioner matrix is determined by analyzing // the visibility structure of the scene, i.e. which cameras see which // points. // -// Strictly speaking, SCHUR_JACOBI is not a visibility based -// preconditioner but it is an extreme case of CLUSTER_JACOBI, where -// every cluster contains exactly one camera block. Treating it as a -// special case of CLUSTER_JACOBI makes it easy to implement as part -// of the same code base with no significant loss of performance. -// -// In the following, we will only discuss CLUSTER_JACOBI and -// CLUSTER_TRIDIAGONAL. -// // The key idea of visibility based preconditioning is to identify // cameras that we expect have strong interactions, and then using the // entries in the Schur complement matrix corresponding to these @@ -130,15 +114,15 @@ class SchurEliminatorBase; // // LinearSolver::Options options; // options.preconditioner_type = CLUSTER_JACOBI; -// options.num_eliminate_blocks = num_points; +// options.elimination_groups.push_back(num_points); +// options.elimination_groups.push_back(num_cameras); // VisibilityBasedPreconditioner preconditioner( // *A.block_structure(), options); // preconditioner.Update(A, NULL); // preconditioner.RightMultiply(x, y); // - #ifndef CERES_NO_SUITESPARSE -class VisibilityBasedPreconditioner : public LinearOperator { +class VisibilityBasedPreconditioner : public Preconditioner { public: // Initialize the symbolic structure of the preconditioner. bs is // the block structure of the linear system to be solved. It is used @@ -146,48 +130,17 @@ class VisibilityBasedPreconditioner : public LinearOperator { // // It has the same structural requirement as other Schur complement // based solvers. Please see schur_eliminator.h for more details. - // - // LinearSolver::Options::num_eliminate_blocks should be set to the - // number of e_blocks in the block structure. - // - // TODO(sameeragarwal): The use of LinearSolver::Options should - // ultimately be replaced with Preconditioner::Options and some sort - // of preconditioner factory along the lines of - // LinearSolver::CreateLinearSolver. I will wait to do this till I - // create a general purpose block Jacobi preconditioner for general - // sparse problems along with a CGLS solver. VisibilityBasedPreconditioner(const CompressedRowBlockStructure& bs, - const LinearSolver::Options& options); + const Preconditioner::Options& options); virtual ~VisibilityBasedPreconditioner(); - // Update the numerical value of the preconditioner for the linear - // system: - // - // | A | x = |b| - // |diag(D)| |0| - // - // for some vector b. It is important that the matrix A have the - // same block structure as the one used to construct this object. - // - // D can be NULL, in which case its interpreted as a diagonal matrix - // of size zero. - bool Update(const BlockSparseMatrixBase& A, const double* D); - - - // LinearOperator interface. Since the operator is symmetric, - // LeftMultiply and num_cols are just calls to RightMultiply and - // num_rows respectively. Update() must be called before - // RightMultiply can be called. + // Preconditioner interface + virtual bool Update(const BlockSparseMatrixBase& A, const double* D); virtual void RightMultiply(const double* x, double* y) const; - virtual void LeftMultiply(const double* x, double* y) const { - RightMultiply(x, y); - } virtual int num_rows() const; - virtual int num_cols() const { return num_rows(); } friend class VisibilityBasedPreconditionerTest; private: - void ComputeSchurJacobiSparsity(const CompressedRowBlockStructure& bs); void ComputeClusterJacobiSparsity(const CompressedRowBlockStructure& bs); void ComputeClusterTridiagonalSparsity(const CompressedRowBlockStructure& bs); void InitStorage(const CompressedRowBlockStructure& bs); @@ -207,7 +160,7 @@ class VisibilityBasedPreconditioner : public LinearOperator { bool IsBlockPairInPreconditioner(int block1, int block2) const; bool IsBlockPairOffDiagonal(int block1, int block2) const; - LinearSolver::Options options_; + Preconditioner::Options options_; // Number of parameter blocks in the schur complement. int num_blocks_; @@ -249,10 +202,10 @@ class VisibilityBasedPreconditioner : public LinearOperator { #else // SuiteSparse // If SuiteSparse is not compiled in, the preconditioner is not // available. -class VisibilityBasedPreconditioner : public LinearOperator { +class VisibilityBasedPreconditioner : public Preconditioner { public: VisibilityBasedPreconditioner(const CompressedRowBlockStructure& bs, - const LinearSolver::Options& options) { + const Preconditioner::Options& options) { LOG(FATAL) << "Visibility based preconditioning is not available. Please " "build Ceres with SuiteSparse."; } diff --git a/extern/libmv/third_party/ceres/internal/ceres/wall_time.cc b/extern/libmv/third_party/ceres/internal/ceres/wall_time.cc new file mode 100644 index 00000000000..e63d20c0ab1 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/wall_time.cc @@ -0,0 +1,96 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: strandmark@google.com (Petter Strandmark) + +#include "ceres/wall_time.h" + +#ifdef CERES_USE_OPENMP +#include +#else +#include +#endif + +#ifdef _WIN32 +#include +#else +#include +#endif + +namespace ceres { +namespace internal { + +double WallTimeInSeconds() { +#ifdef CERES_USE_OPENMP + return omp_get_wtime(); +#else +#ifdef _WIN32 + return static_cast(std::time(NULL)); +#else + timeval time_val; + gettimeofday(&time_val, NULL); + return (time_val.tv_sec + time_val.tv_usec * 1e-6); +#endif +#endif +} + +EventLogger::EventLogger(const string& logger_name) + : start_time_(WallTimeInSeconds()), + last_event_time_(start_time_), + events_("") { + StringAppendF(&events_, + "\n%s\n Delta Cumulative\n", + logger_name.c_str()); +} + +EventLogger::~EventLogger() { + if (VLOG_IS_ON(3)) { + AddEvent("Total"); + VLOG(2) << "\n" << events_ << "\n"; + } +} + +void EventLogger::AddEvent(const string& event_name) { + if (!VLOG_IS_ON(3)) { + return; + } + + const double current_time = WallTimeInSeconds(); + const double relative_time_delta = current_time - last_event_time_; + const double absolute_time_delta = current_time - start_time_; + last_event_time_ = current_time; + + StringAppendF(&events_, + " %25s : %10.5f %10.5f\n", + event_name.c_str(), + relative_time_delta, + absolute_time_delta); +} + +} // namespace internal +} // namespace ceres diff --git a/extern/libmv/third_party/ceres/internal/ceres/wall_time.h b/extern/libmv/third_party/ceres/internal/ceres/wall_time.h new file mode 100644 index 00000000000..45f65ca1aa5 --- /dev/null +++ b/extern/libmv/third_party/ceres/internal/ceres/wall_time.h @@ -0,0 +1,88 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: strandmark@google.com (Petter Strandmark) + +#ifndef CERES_INTERNAL_WALL_TIME_H_ +#define CERES_INTERNAL_WALL_TIME_H_ + +#include + +#include "ceres/internal/port.h" +#include "ceres/stringprintf.h" +#include "glog/logging.h" + +namespace ceres { +namespace internal { + +// Returns time, in seconds, from some arbitrary starting point. If +// OpenMP is available then the high precision openmp_get_wtime() +// function is used. Otherwise on unixes, gettimeofday is used. The +// granularity is in seconds on windows systems. +double WallTimeInSeconds(); + +// Log a series of events, recording for each event the time elapsed +// since the last event and since the creation of the object. +// +// The information is output to VLOG(3) upon destruction. A +// name::Total event is added as the final event right before +// destruction. +// +// Example usage: +// +// void Foo() { +// EventLogger event_logger("Foo"); +// Bar1(); +// event_logger.AddEvent("Bar1") +// Bar2(); +// event_logger.AddEvent("Bar2") +// Bar3(); +// } +// +// Will produce output that looks like +// +// Foo +// Bar1: time1 time1 +// Bar2: time2 time1 + time2; +// Total: time3 time1 + time2 + time3; +class EventLogger { + public: + explicit EventLogger(const string& logger_name); + ~EventLogger(); + void AddEvent(const string& event_name); + + private: + const double start_time_; + double last_event_time_; + string events_; +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_WALL_TIME_H_ diff --git a/extern/libmv/third_party/ceres/patches/collections_port.h.mingw.patch b/extern/libmv/third_party/ceres/patches/collections_port.h.mingw.patch deleted file mode 100644 index c01a17c7992..00000000000 --- a/extern/libmv/third_party/ceres/patches/collections_port.h.mingw.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/internal/ceres/collections_port.h b/internal/ceres/collections_port.h -index a356cc0..c2fce90 100644 ---- a/internal/ceres/collections_port.h -+++ b/internal/ceres/collections_port.h -@@ -77,7 +77,7 @@ struct HashMap : std::tr1::unordered_map {}; - template - struct HashSet : std::tr1::unordered_set {}; - --#ifdef _WIN32 -+#if defined(_WIN32) && !defined(__MINGW64__) && !defined(__MINGW32__) - #define GG_LONGLONG(x) x##I64 - #define GG_ULONGLONG(x) x##UI64 - #else diff --git a/extern/libmv/third_party/ceres/patches/msvc_glog_fix.patch b/extern/libmv/third_party/ceres/patches/msvc_glog_fix.patch deleted file mode 100644 index f3200fb8e0a..00000000000 --- a/extern/libmv/third_party/ceres/patches/msvc_glog_fix.patch +++ /dev/null @@ -1,50 +0,0 @@ -diff --git a/internal/ceres/block_random_access_dense_matrix.cc b/internal/ceres/block_random_access_dense_matrix.cc -index aedfc74..0f95e89 100644 ---- a/internal/ceres/block_random_access_dense_matrix.cc -+++ b/internal/ceres/block_random_access_dense_matrix.cc -@@ -28,12 +28,12 @@ - // - // Author: sameeragarwal@google.com (Sameer Agarwal) - -+#include "glog/logging.h" - #include "ceres/block_random_access_dense_matrix.h" - - #include - #include "ceres/internal/eigen.h" - #include "ceres/internal/scoped_ptr.h" --#include "glog/logging.h" - - namespace ceres { - namespace internal { -diff --git a/internal/ceres/block_random_access_sparse_matrix.cc b/internal/ceres/block_random_access_sparse_matrix.cc -index f789436..9ed62ce 100644 ---- a/internal/ceres/block_random_access_sparse_matrix.cc -+++ b/internal/ceres/block_random_access_sparse_matrix.cc -@@ -28,6 +28,7 @@ - // - // Author: sameeragarwal@google.com (Sameer Agarwal) - -+#include "glog/logging.h" - #include "ceres/block_random_access_sparse_matrix.h" - - #include -@@ -39,7 +40,6 @@ - #include "ceres/mutex.h" - #include "ceres/triplet_sparse_matrix.h" - #include "ceres/types.h" --#include "glog/logging.h" - - namespace ceres { - namespace internal { -diff --git a/internal/ceres/schur_complement_solver.cc b/internal/ceres/schur_complement_solver.cc -index b9224d8..2cbe78d 100644 ---- a/internal/ceres/schur_complement_solver.cc -+++ b/internal/ceres/schur_complement_solver.cc -@@ -38,6 +38,7 @@ - #endif // CERES_NO_CXSPARSE - - #include "Eigen/Dense" -+#include "glog/logging.h" - #include "ceres/block_random_access_dense_matrix.h" - #include "ceres/block_random_access_matrix.h" - #include "ceres/block_random_access_sparse_matrix.h" diff --git a/extern/libmv/third_party/ceres/patches/no_previous_declaration_fix.patch b/extern/libmv/third_party/ceres/patches/no_previous_declaration_fix.patch deleted file mode 100644 index 03f1c500d9a..00000000000 --- a/extern/libmv/third_party/ceres/patches/no_previous_declaration_fix.patch +++ /dev/null @@ -1,199 +0,0 @@ -diff --git a/internal/ceres/file.cc b/internal/ceres/file.cc -index 387f359..6fe7557 100644 ---- a/internal/ceres/file.cc -+++ b/internal/ceres/file.cc -@@ -31,6 +31,7 @@ - // Really simple file IO. - - #include -+#include "file.h" - #include "glog/logging.h" - - namespace ceres { -diff --git a/internal/ceres/linear_least_squares_problems.cc b/internal/ceres/linear_least_squares_problems.cc -index 3e3bcd0..a91e254 100644 ---- a/internal/ceres/linear_least_squares_problems.cc -+++ b/internal/ceres/linear_least_squares_problems.cc -@@ -573,13 +573,13 @@ LinearLeastSquaresProblem* LinearLeastSquaresProblem3() { - return problem; - } - --bool DumpLinearLeastSquaresProblemToConsole(const string& directory, -- int iteration, -- const SparseMatrix* A, -- const double* D, -- const double* b, -- const double* x, -- int num_eliminate_blocks) { -+static bool DumpLinearLeastSquaresProblemToConsole(const string& directory, -+ int iteration, -+ const SparseMatrix* A, -+ const double* D, -+ const double* b, -+ const double* x, -+ int num_eliminate_blocks) { - CHECK_NOTNULL(A); - Matrix AA; - A->ToDenseMatrix(&AA); -@@ -601,13 +601,13 @@ bool DumpLinearLeastSquaresProblemToConsole(const string& directory, - }; - - #ifndef CERES_NO_PROTOCOL_BUFFERS --bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, -- int iteration, -- const SparseMatrix* A, -- const double* D, -- const double* b, -- const double* x, -- int num_eliminate_blocks) { -+static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, -+ int iteration, -+ const SparseMatrix* A, -+ const double* D, -+ const double* b, -+ const double* x, -+ int num_eliminate_blocks) { - CHECK_NOTNULL(A); - LinearLeastSquaresProblemProto lsqp; - A->ToProto(lsqp.mutable_a()); -@@ -641,13 +641,13 @@ bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, - return true; - } - #else --bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, -- int iteration, -- const SparseMatrix* A, -- const double* D, -- const double* b, -- const double* x, -- int num_eliminate_blocks) { -+static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, -+ int iteration, -+ const SparseMatrix* A, -+ const double* D, -+ const double* b, -+ const double* x, -+ int num_eliminate_blocks) { - LOG(ERROR) << "Dumping least squares problems is only " - << "supported when Ceres is compiled with " - << "protocol buffer support."; -@@ -655,9 +655,9 @@ bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory, - } - #endif - --void WriteArrayToFileOrDie(const string& filename, -- const double* x, -- const int size) { -+static void WriteArrayToFileOrDie(const string& filename, -+ const double* x, -+ const int size) { - CHECK_NOTNULL(x); - VLOG(2) << "Writing array to: " << filename; - FILE* fptr = fopen(filename.c_str(), "w"); -@@ -668,13 +668,13 @@ void WriteArrayToFileOrDie(const string& filename, - fclose(fptr); - } - --bool DumpLinearLeastSquaresProblemToTextFile(const string& directory, -- int iteration, -- const SparseMatrix* A, -- const double* D, -- const double* b, -- const double* x, -- int num_eliminate_blocks) { -+static bool DumpLinearLeastSquaresProblemToTextFile(const string& directory, -+ int iteration, -+ const SparseMatrix* A, -+ const double* D, -+ const double* b, -+ const double* x, -+ int num_eliminate_blocks) { - CHECK_NOTNULL(A); - string format_string = JoinPath(directory, - "lm_iteration_%03d"); -diff --git a/internal/ceres/residual_block_utils.cc b/internal/ceres/residual_block_utils.cc -index ff18e21..9442bb2 100644 ---- a/internal/ceres/residual_block_utils.cc -+++ b/internal/ceres/residual_block_utils.cc -@@ -63,7 +63,7 @@ void InvalidateEvaluation(const ResidualBlock& block, - - // Utility routine to print an array of doubles to a string. If the - // array pointer is NULL, it is treated as an array of zeros. --void AppendArrayToString(const int size, const double* x, string* result) { -+static void AppendArrayToString(const int size, const double* x, string* result) { - for (int i = 0; i < size; ++i) { - if (x == NULL) { - StringAppendF(result, "Not Computed "); -diff --git a/internal/ceres/solver_impl.cc b/internal/ceres/solver_impl.cc -index 2802a75..8ef5b98 100644 ---- a/internal/ceres/solver_impl.cc -+++ b/internal/ceres/solver_impl.cc -@@ -685,8 +685,8 @@ bool SolverImpl::ApplyUserOrdering(const ProblemImpl& problem_impl, - // Find the minimum index of any parameter block to the given residual. - // Parameter blocks that have indices greater than num_eliminate_blocks are - // considered to have an index equal to num_eliminate_blocks. --int MinParameterBlock(const ResidualBlock* residual_block, -- int num_eliminate_blocks) { -+static int MinParameterBlock(const ResidualBlock* residual_block, -+ int num_eliminate_blocks) { - int min_parameter_block_position = num_eliminate_blocks; - for (int i = 0; i < residual_block->NumParameterBlocks(); ++i) { - ParameterBlock* parameter_block = residual_block->parameter_blocks()[i]; -diff --git a/internal/ceres/split.cc b/internal/ceres/split.cc -index 4fa1bd4..c65c8a5 100644 ---- a/internal/ceres/split.cc -+++ b/internal/ceres/split.cc -@@ -31,6 +31,7 @@ - #include - #include - #include -+#include "ceres/split.h" - #include "ceres/internal/port.h" - - namespace ceres { -diff --git a/internal/ceres/stringprintf.cc b/internal/ceres/stringprintf.cc -index c0f3522..396a48b 100644 ---- a/internal/ceres/stringprintf.cc -+++ b/internal/ceres/stringprintf.cc -@@ -34,6 +34,7 @@ - #include - #include - -+#include "ceres/stringprintf.h" - #include "ceres/internal/port.h" - - namespace ceres { -diff --git a/internal/ceres/types.cc b/internal/ceres/types.cc -index 2e950c5..05e573f 100644 ---- a/internal/ceres/types.cc -+++ b/internal/ceres/types.cc -@@ -98,7 +98,8 @@ const char* SolverTerminationTypeToString( - } - } - --const char* SparseLinearAlgebraTypeToString( -+#if 0 /* UNUSED */ -+static const char* SparseLinearAlgebraTypeToString( - SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type) { - switch (sparse_linear_algebra_library_type) { - CASESTR(CX_SPARSE); -@@ -107,6 +108,7 @@ const char* SparseLinearAlgebraTypeToString( - return "UNKNOWN"; - } - } -+#endif - - const char* TrustRegionStrategyTypeToString( - TrustRegionStrategyType trust_region_strategy_type) { -diff --git a/internal/ceres/visibility.cc b/internal/ceres/visibility.cc -index 9d80654..564cc54 100644 ---- a/internal/ceres/visibility.cc -+++ b/internal/ceres/visibility.cc -@@ -36,6 +36,7 @@ - #include - #include "ceres/block_structure.h" - #include "ceres/collections_port.h" -+#include "ceres/visibility.h" - #include "ceres/graph.h" - #include "glog/logging.h" - diff --git a/extern/libmv/third_party/ceres/patches/series b/extern/libmv/third_party/ceres/patches/series index a6874318923..e69de29bb2d 100644 --- a/extern/libmv/third_party/ceres/patches/series +++ b/extern/libmv/third_party/ceres/patches/series @@ -1,3 +0,0 @@ -collections_port.h.mingw.patch -msvc_glog_fix.patch -no_previous_declaration_fix.patch \ No newline at end of file -- cgit v1.2.3 From 12baa00b6a9aef7622f46b572bef0be9af4d647d Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 25 Feb 2013 09:24:31 +0000 Subject: code cleanup: camera tracking - Moved keyframes and refirement flags into reconstruction options structure - Moved distortion coefficients and other camera intrinsics into own structure - Cleaned up reconstruction functions in libmv c-api --- svn merge -r52853:52854 ^/branches/soc-2011-tomato --- extern/libmv/libmv-capi.cpp | 126 ++++++++++++++++++++++++++++---------------- extern/libmv/libmv-capi.h | 38 ++++++++----- 2 files changed, 105 insertions(+), 59 deletions(-) (limited to 'extern') diff --git a/extern/libmv/libmv-capi.cpp b/extern/libmv/libmv-capi.cpp index 8e483abd386..ffe4b6ebf3d 100644 --- a/extern/libmv/libmv-capi.cpp +++ b/extern/libmv/libmv-capi.cpp @@ -552,40 +552,78 @@ static void libmv_solveRefineIntrinsics(libmv::Tracks *tracks, libmv::CameraIntr reconstruction, intrinsics); } -libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyframe1, int keyframe2, - int refine_intrinsics, double focal_length, double principal_x, double principal_y, - double k1, double k2, double k3, struct libmv_reconstructionOptions *options, - reconstruct_progress_update_cb progress_update_callback, void *callback_customdata) +static void cameraIntrinsicsFromOptions(libmv::CameraIntrinsics *camera_intrinsics, + libmv_cameraIntrinsicsOptions *camera_intrinsics_options) +{ + camera_intrinsics->SetFocalLength(camera_intrinsics_options->focal_length, + camera_intrinsics_options->focal_length); + + camera_intrinsics->SetPrincipalPoint(camera_intrinsics_options->principal_point_x, + camera_intrinsics_options->principal_point_y); + + camera_intrinsics->SetRadialDistortion(camera_intrinsics_options->k1, + camera_intrinsics_options->k2, + camera_intrinsics_options->k3); +} + +static libmv::Tracks getNormalizedTracks(libmv::Tracks *tracks, libmv::CameraIntrinsics *camera_intrinsics) +{ + libmv::vector markers = tracks->AllMarkers(); + + for (int i = 0; i < markers.size(); ++i) { + camera_intrinsics->InvertIntrinsics(markers[i].x, markers[i].y, + &(markers[i].x), &(markers[i].y)); + } + + return libmv::Tracks(markers); +} + +static void finishReconstruction(libmv::Tracks *tracks, libmv::CameraIntrinsics *camera_intrinsics, + libmv_Reconstruction *libmv_reconstruction, + reconstruct_progress_update_cb progress_update_callback, + void *callback_customdata) +{ + libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction; + + /* reprojection error calculation */ + progress_update_callback(callback_customdata, 1.0, "Finishing solution"); + libmv_reconstruction->tracks = *tracks; + libmv_reconstruction->error = libmv::EuclideanReprojectionError(*tracks, *reconstruction, *camera_intrinsics); +} + +libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *libmv_tracks, + libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, + libmv_reconstructionOptions *libmv_reconstruction_options, + reconstruct_progress_update_cb progress_update_callback, + void *callback_customdata) { - /* Invert the camera intrinsics. */ - libmv::vector markers = ((libmv::Tracks*)tracks)->AllMarkers(); libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction(); + + libmv::Tracks *tracks = ((libmv::Tracks *) libmv_tracks); libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction; - libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics; - libmv::ReconstructionOptions reconstruction_options; + libmv::CameraIntrinsics *camera_intrinsics = &libmv_reconstruction->intrinsics; ReconstructUpdateCallback update_callback = ReconstructUpdateCallback(progress_update_callback, callback_customdata); - intrinsics->SetFocalLength(focal_length, focal_length); - intrinsics->SetPrincipalPoint(principal_x, principal_y); - intrinsics->SetRadialDistortion(k1, k2, k3); + cameraIntrinsicsFromOptions(camera_intrinsics, libmv_camera_intrinsics_options); - reconstruction_options.success_threshold = options->success_threshold; - reconstruction_options.use_fallback_reconstruction = options->use_fallback_reconstruction; + /* Invert the camera intrinsics */ + libmv::Tracks normalized_tracks = getNormalizedTracks(tracks, camera_intrinsics); - for (int i = 0; i < markers.size(); ++i) { - intrinsics->InvertIntrinsics(markers[i].x, - markers[i].y, - &(markers[i].x), - &(markers[i].y)); - } + /* actual reconstruction */ + libmv::ReconstructionOptions reconstruction_options; + reconstruction_options.success_threshold = libmv_reconstruction_options->success_threshold; + reconstruction_options.use_fallback_reconstruction = libmv_reconstruction_options->use_fallback_reconstruction; - libmv::Tracks normalized_tracks(markers); + int keyframe1 = libmv_reconstruction_options->keyframe1, + keyframe2 = libmv_reconstruction_options->keyframe2; LG << "frames to init from: " << keyframe1 << " " << keyframe2; + libmv::vector keyframe_markers = normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2); + LG << "number of markers for init: " << keyframe_markers.size(); update_callback.invoke(0, "Initial reconstruction"); @@ -595,49 +633,45 @@ libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyfra libmv::EuclideanCompleteReconstruction(reconstruction_options, normalized_tracks, reconstruction, &update_callback); - if (refine_intrinsics) { - libmv_solveRefineIntrinsics((libmv::Tracks *)tracks, intrinsics, reconstruction, - refine_intrinsics, progress_update_callback, callback_customdata); + /* refinement */ + if (libmv_reconstruction_options->refine_intrinsics) { + libmv_solveRefineIntrinsics((libmv::Tracks *)tracks, camera_intrinsics, reconstruction, + libmv_reconstruction_options->refine_intrinsics, + progress_update_callback, callback_customdata); } - progress_update_callback(callback_customdata, 1.0, "Finishing solution"); - libmv_reconstruction->tracks = *(libmv::Tracks *)tracks; - libmv_reconstruction->error = libmv::EuclideanReprojectionError(*(libmv::Tracks *)tracks, *reconstruction, *intrinsics); + /* finish reconstruction */ + finishReconstruction(tracks, camera_intrinsics, libmv_reconstruction, + progress_update_callback, callback_customdata); return (libmv_Reconstruction *)libmv_reconstruction; } -struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *tracks, double focal_length, - double principal_x, double principal_y, double k1, double k2, double k3, - reconstruct_progress_update_cb progress_update_callback, void *callback_customdata) +struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *libmv_tracks, + libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, + reconstruct_progress_update_cb progress_update_callback, + void *callback_customdata) { - /* Invert the camera intrinsics. */ - libmv::vector markers = ((libmv::Tracks*)tracks)->AllMarkers(); libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction(); + + libmv::Tracks *tracks = ((libmv::Tracks *) libmv_tracks); libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction; - libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics; + libmv::CameraIntrinsics *camera_intrinsics = &libmv_reconstruction->intrinsics; ReconstructUpdateCallback update_callback = ReconstructUpdateCallback(progress_update_callback, callback_customdata); - intrinsics->SetFocalLength(focal_length, focal_length); - intrinsics->SetPrincipalPoint(principal_x, principal_y); - intrinsics->SetRadialDistortion(k1, k2, k3); - - for (int i = 0; i < markers.size(); ++i) { - intrinsics->InvertIntrinsics(markers[i].x, - markers[i].y, - &(markers[i].x), - &(markers[i].y)); - } + cameraIntrinsicsFromOptions(camera_intrinsics, libmv_camera_intrinsics_options); - libmv::Tracks normalized_tracks(markers); + /* Invert the camera intrinsics */ + libmv::Tracks normalized_tracks = getNormalizedTracks(tracks, camera_intrinsics); + /* actual reconstruction */ libmv::ModalSolver(normalized_tracks, reconstruction, &update_callback); - progress_update_callback(callback_customdata, 1.0, "Finishing solution"); - libmv_reconstruction->tracks = *(libmv::Tracks *)tracks; - libmv_reconstruction->error = libmv::EuclideanReprojectionError(*(libmv::Tracks *)tracks, *reconstruction, *intrinsics); + /* finish reconstruction */ + finishReconstruction(tracks, camera_intrinsics, libmv_reconstruction, + progress_update_callback, callback_customdata); return (libmv_Reconstruction *)libmv_reconstruction; } diff --git a/extern/libmv/libmv-capi.h b/extern/libmv/libmv-capi.h index e5885e7addf..317f5520aa9 100644 --- a/extern/libmv/libmv-capi.h +++ b/extern/libmv/libmv-capi.h @@ -86,28 +86,40 @@ void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track, void libmv_tracksDestroy(struct libmv_Tracks *libmv_tracks); /* Reconstruction solver */ -#define LIBMV_REFINE_FOCAL_LENGTH (1<<0) -#define LIBMV_REFINE_PRINCIPAL_POINT (1<<1) -#define LIBMV_REFINE_RADIAL_DISTORTION_K1 (1<<2) -#define LIBMV_REFINE_RADIAL_DISTORTION_K2 (1<<4) -/* TODO: make keyframes/distortion model a part of options? */ -struct libmv_reconstructionOptions { +#define LIBMV_REFINE_FOCAL_LENGTH (1 << 0) +#define LIBMV_REFINE_PRINCIPAL_POINT (1 << 1) +#define LIBMV_REFINE_RADIAL_DISTORTION_K1 (1 << 2) +#define LIBMV_REFINE_RADIAL_DISTORTION_K2 (1 << 4) + +typedef struct libmv_cameraIntrinsicsOptions { + double focal_length; + double principal_point_x, principal_point_y; + double k1, k2, k3; + double p1, p2; +} libmv_cameraIntrinsicsOptions; + +typedef struct libmv_reconstructionOptions { + int keyframe1, keyframe2; + int refine_intrinsics; + double success_threshold; int use_fallback_reconstruction; -}; +} libmv_reconstructionOptions; typedef void (*reconstruct_progress_update_cb) (void *customdata, double progress, const char *message); int libmv_refineParametersAreValid(int parameters); -struct libmv_Reconstruction *libmv_solveReconstruction(struct libmv_Tracks *tracks, int keyframe1, int keyframe2, - int refine_intrinsics, double focal_length, double principal_x, double principal_y, double k1, double k2, double k3, - struct libmv_reconstructionOptions *options, reconstruct_progress_update_cb progress_update_callback, +struct libmv_Reconstruction *libmv_solveReconstruction(struct libmv_Tracks *libmv_tracks, + libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, + libmv_reconstructionOptions *libmv_reconstruction_options, + reconstruct_progress_update_cb progress_update_callback, + void *callback_customdata); +struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *libmv_tracks, + libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, + reconstruct_progress_update_cb progress_update_callback, void *callback_customdata); -struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *tracks, double focal_length, - double principal_x, double principal_y, double k1, double k2, double k3, - reconstruct_progress_update_cb progress_update_callback, void *callback_customdata); int libmv_reporojectionPointForTrack(struct libmv_Reconstruction *libmv_reconstruction, int track, double pos[3]); double libmv_reporojectionErrorForTrack(struct libmv_Reconstruction *libmv_reconstruction, int track); double libmv_reporojectionErrorForImage(struct libmv_Reconstruction *libmv_reconstruction, int image); -- cgit v1.2.3 From a0d646d1869162806a2d7050d748669978dd94db Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 25 Feb 2013 09:27:57 +0000 Subject: Synchronize libmv with own branch Should be no functional changes, just would help a lot checking on which stuff was/shall be merged from tomato and which is not. --- extern/libmv/ChangeLog | 130 +++++++++++++++++++++------- extern/libmv/libmv/multiview/fundamental.cc | 4 +- extern/libmv/libmv/multiview/homography.cc | 15 ++++ extern/libmv/libmv/multiview/homography.h | 8 ++ 4 files changed, 123 insertions(+), 34 deletions(-) (limited to 'extern') diff --git a/extern/libmv/ChangeLog b/extern/libmv/ChangeLog index c52d5456c32..222fc4eaa1f 100644 --- a/extern/libmv/ChangeLog +++ b/extern/libmv/ChangeLog @@ -1,3 +1,101 @@ +commit 575336f794841ada90aacd783285014081b8318c +Author: Sergey Sharybin +Date: Mon Jan 7 15:58:40 2013 +0600 + + Fixed for keyframe selection + + - Calculate residuals for GRIC in pixel space rather than + in normalized space. + + This seems to be how it's intended to be used. + + Algebraic H and F will still use normalized coordinates which + are more stable, after this matrices are converted to pixel + space and Ceres refinement happens in pixel space. + + - Standard deviation calculation was wrong in GRIC. It shouldn't + be deviation of residuals, but as per Torr it should be deviation + of measurement error, which is constant (in our case 0.1) + + Not sure if using squared cost function is correct for GRIC, + but cost function is indeed squared and in most papers cost + function is used for GRIC. After some further tests we could + switch GRIC residuals to non-squared distance. + + - Bring back rho part of GRIC, in unit tests it doesn't make + sense whether it's enabled or not, lets see how it'll behave + in real-life footage. + + - Added one more unit test based on elevator scene and manual + keyframe selection. + +commit 24117f3c3fc5531beb6497d79bb6f1780a998081 +Author: Sergey Sharybin +Date: Sun Jan 6 19:07:06 2013 +0600 + + Added test for keyframe selection based on manual selection + + Additional changes: + + - Reduce minimal correspondence to match real-world manually + tracked footage + + - Returned back squares to SymmetricEpipolarDistance and + SymmetricGeometricDistance -- this is actually a cost + functions, not distances and they shall be squared. + +commit 770eb0293b881c4c419c587a6cdb062c47ab6e44 +Author: Sergey Sharybin +Date: Fri Dec 21 00:43:30 2012 +0600 + + Improvements for keyframe selection + + - Changed main keyframe selection cycle, so in cases there're no + more next keyframes for current keyframe could be found in the + image sequence, current keyframe would be moved forward and + search continues. + + This helps in cases when there's poor motion in the beginning + of the sequence, then markers becomes occluded. There could be + good keyframes in the middle of the shot still. + + - Extended keyframe_selection_test with real world cases. + + - Moved correspondences constraint to the top, so no H/F estimation + happens if there's bad correspondence. Makes algorithm go a bit + faster. + + Strangely, but using non-squared distances makes neighbor frames + test fail, using squared distances makes this tests pass. + + However, using non-squared distances seems to be working better + in real tests i've been doing. So this requires more investigation/ + +commit 7415c62fbda36c5bd1c291bc94d535a66da896d0 +Author: Sergey Sharybin +Date: Thu Dec 20 18:46:09 2012 +0600 + + Cosmetic change to correspondences reports in keyframe selection + +commit ceaf80c987ec0338e7e83965bc808411453eb755 +Author: Sergey Sharybin +Date: Thu Dec 20 18:08:03 2012 +0600 + + Various fixes: + + - That was a typo in symmetric geometric cost functor, which + computed inverse distance in a wrong way. + + - Fixed compilation of unit tests + + - Added simple test for keyframe selection. Currently only + covers case that neighbor frames with only translation + (homography should be better than fundamental) are not + considered a keyframes. + + Still need to be investigated why it only works if tracks + are in pixel space and why doesn't work in normalized space. + commit cfabdfe48df2add3d1f30cf4370efd0b31990ab0 Author: Sergey Sharybin Date: Thu Dec 20 05:46:53 2012 +0600 @@ -690,35 +788,3 @@ Author: Sergey Sharybin Date: Fri Feb 17 21:32:05 2012 +0600 Picky edits: corrected EOL - -commit 3f2a4205ec5adadcdfa306b161c705c868a7be93 -Author: Sergey Sharybin -Date: Fri Feb 17 21:30:07 2012 +0600 - - Fixed incorrect access to ucontext on linux. Caused by incorrect merge conflict resolve. - -commit d360a21a5aa125cf9e83dd26b302508688ff7007 -Author: Sergey Sharybin -Date: Fri Feb 17 20:54:13 2012 +0600 - - More Windows -> Unix EOL conversions - -commit 18aeda58bec9556140ba617724e31ada6f5b67c0 -Author: Sergey Sharybin -Date: Fri Feb 17 20:15:42 2012 +0600 - - Looks like this debug output was removed accidentally. - -commit 189dc0cacdee3c1eab68c43263ecb038ed244c09 -Author: Sergey Sharybin -Date: Fri Feb 17 20:11:56 2012 +0600 - - Made V3D verbose again by default - -commit 8b3422d3eec5e450d76243886bf07fb0a3e83a81 -Author: Sergey Sharybin -Date: Fri Feb 17 20:08:01 2012 +0600 - - SAD tracker now can deal with pattern size any size, - Very quick implementation came from Blender before Hybrid tracker was added. - Better to be replaced with brute tracker. diff --git a/extern/libmv/libmv/multiview/fundamental.cc b/extern/libmv/libmv/multiview/fundamental.cc index 12a611c748f..80f155e804d 100644 --- a/extern/libmv/libmv/multiview/fundamental.cc +++ b/extern/libmv/libmv/multiview/fundamental.cc @@ -254,8 +254,8 @@ double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) { Vec3 Ft_y = F.transpose() * y; double y_F_x = y.dot(F_x); - return y_F_x * ( 1 / F_x.head<2>().norm() - + 1 / Ft_y.head<2>().norm()); + return Square(y_F_x) * ( 1 / F_x.head<2>().squaredNorm() + + 1 / Ft_y.head<2>().squaredNorm()); } // HZ 9.6 pag 257 (formula 9.12) diff --git a/extern/libmv/libmv/multiview/homography.cc b/extern/libmv/libmv/multiview/homography.cc index b5c483998d8..538c62598c0 100644 --- a/extern/libmv/libmv/multiview/homography.cc +++ b/extern/libmv/libmv/multiview/homography.cc @@ -264,4 +264,19 @@ bool Homography3DFromCorrespondencesLinear(const Mat &x1, return false; } } + +double SymmetricGeometricDistance(Mat3 &H, Vec2 &x1, Vec2 &x2) { + Vec3 x(x1(0), x1(1), 1.0); + Vec3 y(x2(0), x2(1), 1.0); + + Vec3 H_x = H * x; + Vec3 Hinv_y = H.inverse() * y; + + H_x /= H_x(2); + Hinv_y /= Hinv_y(2); + + return (H_x.head<2>() - y.head<2>()).squaredNorm() + + (Hinv_y.head<2>() - x.head<2>()).squaredNorm(); +} + } // namespace libmv diff --git a/extern/libmv/libmv/multiview/homography.h b/extern/libmv/libmv/multiview/homography.h index 786fd3df8ca..a295c4366b6 100644 --- a/extern/libmv/libmv/multiview/homography.h +++ b/extern/libmv/libmv/multiview/homography.h @@ -79,6 +79,14 @@ bool Homography3DFromCorrespondencesLinear(const Mat &x1, Mat4 *H, double expected_precision = EigenDouble::dummy_precision()); + +/** + * Calculate symmetric geometric cost: + * + * D(H * x1, x2)^2 + D(H^-1 * x2, x1) + */ +double SymmetricGeometricDistance(Mat3 &H, Vec2 &x1, Vec2 &x2); + } // namespace libmv #endif // LIBMV_MULTIVIEW_HOMOGRAPHY_H_ -- cgit v1.2.3 From 18fd4bd9f48112fae9f7d29ee88d39cdf5d3a95f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 25 Feb 2013 10:02:43 +0000 Subject: Update Carve to newest upstream version with some assorted fixes Perhaps some warnings could be silenced, but not in mood of writing local patches at this moment. They're all harmless anyway. --- extern/carve/bundle.sh | 2 +- extern/carve/files.txt | 174 ++++++++++++------------ extern/carve/include/carve/csg_triangulator.hpp | 2 +- extern/carve/include/carve/geom3d.hpp | 19 ++- extern/carve/include/carve/geom_impl.hpp | 2 +- extern/carve/include/carve/input.hpp | 81 +++++++++-- extern/carve/include/carve/mesh.hpp | 38 +++++- extern/carve/include/carve/mesh_impl.hpp | 59 ++++++-- extern/carve/lib/intersect.cpp | 4 +- extern/carve/lib/intersect_face_division.cpp | 3 +- extern/carve/lib/mesh.cpp | 36 +++-- extern/carve/lib/polyhedron.cpp | 2 +- extern/carve/patches/series | 1 - extern/carve/patches/strict_flags.patch | 22 --- 14 files changed, 284 insertions(+), 161 deletions(-) delete mode 100644 extern/carve/patches/strict_flags.patch (limited to 'extern') diff --git a/extern/carve/bundle.sh b/extern/carve/bundle.sh index 63d32a5993d..c80bf645077 100755 --- a/extern/carve/bundle.sh +++ b/extern/carve/bundle.sh @@ -91,7 +91,7 @@ if(WITH_BOOST) -DCARVE_SYSTEM_BOOST ) - list(APPEND INC + list(APPEND INC_SYS \${BOOST_INCLUDE_DIR} ) endif() diff --git a/extern/carve/files.txt b/extern/carve/files.txt index c3cb9275950..1084c7f5c41 100644 --- a/extern/carve/files.txt +++ b/extern/carve/files.txt @@ -1,107 +1,109 @@ -include/carve/polyhedron_decl.hpp -include/carve/geom2d.hpp -include/carve/exact.hpp -include/carve/triangulator_impl.hpp -include/carve/collection.hpp -include/carve/pointset.hpp -include/carve/djset.hpp -include/carve/kd_node.hpp -include/carve/polyline.hpp -include/carve/polyline_iter.hpp -include/carve/geom3d.hpp -include/carve/edge_decl.hpp -include/carve/face_decl.hpp +include/carve/vertex_impl.hpp include/carve/aabb_impl.hpp -include/carve/colour.hpp +include/carve/csg.hpp include/carve/pointset_iter.hpp -include/carve/polyline_decl.hpp -include/carve/rescale.hpp -include/carve/mesh_impl.hpp -include/carve/classification.hpp -include/carve/util.hpp -include/carve/triangulator.hpp -include/carve/polyhedron_base.hpp -include/carve/rtree.hpp -include/carve/math.hpp -include/carve/math_constants.hpp -include/carve/octree_decl.hpp -include/carve/input.hpp -include/carve/mesh_ops.hpp include/carve/debug_hooks.hpp -include/carve/mesh_simplify.hpp -include/carve/interpolator.hpp -include/carve/poly_decl.hpp -include/carve/csg.hpp include/carve/mesh.hpp -include/carve/carve.hpp -include/carve/gnu_cxx.h -include/carve/polyhedron_impl.hpp -include/carve/poly_impl.hpp -include/carve/aabb.hpp +include/carve/triangulator_impl.hpp +include/carve/edge_decl.hpp +include/carve/collection/unordered.hpp +include/carve/collection/unordered/tr1_impl.hpp +include/carve/collection/unordered/fallback_impl.hpp +include/carve/collection/unordered/std_impl.hpp +include/carve/collection/unordered/vcpp_impl.hpp +include/carve/collection/unordered/libstdcpp_impl.hpp +include/carve/collection/unordered/boost_impl.hpp include/carve/convex_hull.hpp -include/carve/vertex_decl.hpp +include/carve/geom.hpp +include/carve/collection_types.hpp +include/carve/cbrt.h +include/carve/util.hpp +include/carve/iobj.hpp +include/carve/polyline_decl.hpp +include/carve/polyline_impl.hpp include/carve/win32.h include/carve/edge_impl.hpp -include/carve/tag.hpp -include/carve/tree.hpp -include/carve/heap.hpp +include/carve/carve.hpp +include/carve/polyline.hpp +include/carve/config.h +include/carve/face_decl.hpp include/carve/matrix.hpp -include/carve/poly.hpp -include/carve/vector.hpp -include/carve/intersection.hpp -include/carve/faceloop.hpp +include/carve/classification.hpp include/carve/geom_impl.hpp -include/carve/octree_impl.hpp -include/carve/spacetree.hpp -include/carve/collection/unordered/std_impl.hpp -include/carve/collection/unordered/tr1_impl.hpp -include/carve/collection/unordered/libstdcpp_impl.hpp -include/carve/collection/unordered/boost_impl.hpp -include/carve/collection/unordered/vcpp_impl.hpp -include/carve/collection/unordered/fallback_impl.hpp -include/carve/collection/unordered.hpp +include/carve/faceloop.hpp +include/carve/mesh_ops.hpp +include/carve/tree.hpp +include/carve/geom2d.hpp include/carve/face_impl.hpp +include/carve/polyhedron_decl.hpp +include/carve/interpolator.hpp +include/carve/poly_decl.hpp +include/carve/mesh_impl.hpp +include/carve/gnu_cxx.h +include/carve/mesh_simplify.hpp +include/carve/triangulator.hpp include/carve/pointset_impl.hpp -include/carve/cbrt.h +include/carve/rtree.hpp +include/carve/math_constants.hpp +include/carve/vector.hpp +include/carve/octree_impl.hpp +include/carve/pointset.hpp +include/carve/math.hpp +include/carve/intersection.hpp +include/carve/colour.hpp +include/carve/kd_node.hpp +include/carve/input.hpp +include/carve/geom3d.hpp +include/carve/exact.hpp +include/carve/rescale.hpp +include/carve/polyhedron_base.hpp +include/carve/heap.hpp +include/carve/spacetree.hpp +include/carve/polyhedron_impl.hpp include/carve/vcpp_config.h -include/carve/geom.hpp -include/carve/vertex_impl.hpp -include/carve/polyline_impl.hpp -include/carve/pointset_decl.hpp -include/carve/timing.hpp +include/carve/aabb.hpp +include/carve/polyline_iter.hpp +include/carve/djset.hpp +include/carve/vertex_decl.hpp include/carve/csg_triangulator.hpp -include/carve/iobj.hpp -include/carve/collection_types.hpp -lib/carve.cpp -lib/mesh.cpp -lib/intersect_group.cpp -lib/intersect_classify_common.hpp -lib/intersect_classify_edge.cpp -lib/intersect_classify_group.cpp +include/carve/poly.hpp +include/carve/external/boost/random.hpp +include/carve/timing.hpp +include/carve/octree_decl.hpp +include/carve/pointset_decl.hpp +include/carve/tag.hpp +include/carve/collection.hpp +include/carve/poly_impl.hpp +lib/intersection.cpp +lib/intersect.cpp +lib/triangulator.cpp +lib/intersect_debug.hpp +lib/csg_collector.hpp lib/csg_data.hpp +lib/convex_hull.cpp +lib/intersect_classify_common.hpp +lib/intersect_common.hpp lib/polyhedron.cpp -lib/csg_collector.hpp -lib/geom3d.cpp lib/polyline.cpp -lib/csg_collector.cpp -lib/triangulator.cpp -lib/intersect_face_division.cpp -lib/intersect_half_classify_group.cpp -lib/edge.cpp -lib/math.cpp +lib/pointset.cpp lib/geom2d.cpp +lib/math.cpp +lib/intersect_half_classify_group.cpp +lib/intersect_face_division.cpp lib/tag.cpp -lib/intersection.cpp -lib/convex_hull.cpp -lib/intersect_common.hpp -lib/intersect_classify_common_impl.hpp -lib/csg.cpp -lib/intersect.cpp +lib/aabb.cpp +lib/intersect_classify_group.cpp lib/csg_detail.hpp -lib/face.cpp -lib/pointset.cpp +lib/mesh.cpp lib/timing.cpp -lib/octree.cpp -lib/aabb.cpp -lib/intersect_debug.hpp +lib/geom3d.cpp +lib/intersect_group.cpp +lib/carve.cpp +lib/intersect_classify_edge.cpp +lib/csg.cpp +lib/face.cpp +lib/csg_collector.cpp lib/intersect_debug.cpp +lib/edge.cpp +lib/intersect_classify_common_impl.hpp +lib/octree.cpp diff --git a/extern/carve/include/carve/csg_triangulator.hpp b/extern/carve/include/carve/csg_triangulator.hpp index 740585571bf..5a40439271e 100644 --- a/extern/carve/include/carve/csg_triangulator.hpp +++ b/extern/carve/include/carve/csg_triangulator.hpp @@ -174,7 +174,7 @@ namespace carve { double scoreQuad(edge_map_t::iterator i, edge_map_t &edge_map) { if (!(*i).second.first || !(*i).second.second) return -1; - return 0; + return -1; } carve::mesh::MeshSet<3>::face_t *mergeQuad(edge_map_t::iterator i, edge_map_t &edge_map) { diff --git a/extern/carve/include/carve/geom3d.hpp b/extern/carve/include/carve/geom3d.hpp index 90d0672b81e..faeb565b922 100644 --- a/extern/carve/include/carve/geom3d.hpp +++ b/extern/carve/include/carve/geom3d.hpp @@ -206,9 +206,22 @@ namespace carve { * * +1, if a is ordered after b around, rotating about direction. */ inline int compareAngles(const Vector &direction, const Vector &base, const Vector &a, const Vector &b) { - const double d1 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, a, b); - const double d2 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, base, a); - const double d3 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, base, b); + // double d1 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, a, b); + // double d2 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, base, a); + // double d3 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, base, b); + +#if defined(CARVE_USE_EXACT_PREDICATES) + // which is equivalent to the following (which eliminates a + // vector subtraction): + double d1 = carve::geom3d::orient3d(direction, b, a, carve::geom::VECTOR(0,0,0)); + double d2 = carve::geom3d::orient3d(direction, a, base, carve::geom::VECTOR(0,0,0)); + double d3 = carve::geom3d::orient3d(direction, b, base, carve::geom::VECTOR(0,0,0)); +#else + // dotcross = a . (b x c) + double d1 = carve::geom::dotcross(direction, b, a ); + double d2 = carve::geom::dotcross(direction, a, base); + double d3 = carve::geom::dotcross(direction, b, base); +#endif // CASE: a and b are coplanar wrt. direction. if (d1 == 0.0) { diff --git a/extern/carve/include/carve/geom_impl.hpp b/extern/carve/include/carve/geom_impl.hpp index 4463ba2bd88..044655b6c07 100644 --- a/extern/carve/include/carve/geom_impl.hpp +++ b/extern/carve/include/carve/geom_impl.hpp @@ -396,7 +396,7 @@ namespace carve { // Compute a . (b x c) return (a.x * b.y * c.z + a.y * b.z * c.x + a.z * b.x * c.y) - - (a.x * b.z * c.y + a.y * b.x * c.z + a.z * b.y * c.x); + (a.x * c.y * b.z + a.y * c.z * b.x + a.z * c.x * b.y); } diff --git a/extern/carve/include/carve/input.hpp b/extern/carve/include/carve/input.hpp index a8bc8137d6c..4223955c0fd 100644 --- a/extern/carve/include/carve/input.hpp +++ b/extern/carve/include/carve/input.hpp @@ -17,6 +17,9 @@ #pragma once +#include +#include + #include #include #include @@ -28,6 +31,50 @@ namespace carve { namespace input { + typedef std::map Options; + + static inline Options opts() { + return Options(); + } + + static inline Options opts(const char **kv) { + Options r; + for (size_t i = 0; kv[i] != NULL; i += 2) { + r[kv[i]] = kv[i+1]; + } + return r; + } + + static inline Options opts(const std::string &k1, const std::string &v1) { + Options r; + r[k1] = v1; + return r; + } + + static inline Options opts(const std::string &k1, const std::string &v1, + const std::string &k2, const std::string &v2) { + Options r; + r[k1] = v1; + r[k2] = v2; + return r; + } + + static inline Options opts(const std::string &k1, const std::string &v1, + const std::string &k2, const std::string &v2, + const std::string &k3, const std::string &v3) { + Options r; + r[k1] = v1; + r[k2] = v2; + r[k3] = v3; + return r; + } + + static inline bool _bool(const std::string &str, bool _default = false) { + if (str == "true") return true; + if (str == "false") return false; + return _default; + } + struct Data { Data() { } @@ -126,12 +173,18 @@ namespace carve { faceCount = 0; } - carve::poly::Polyhedron *create() const { + carve::poly::Polyhedron *create(const Options &options) const { return new carve::poly::Polyhedron(points, faceCount, faceIndices); } - carve::mesh::MeshSet<3> *createMesh() const { - return new carve::mesh::MeshSet<3>(points, faceCount, faceIndices); + carve::mesh::MeshSet<3> *createMesh(const Options &options) const { + Options::const_iterator i; + carve::mesh::MeshOptions opts; + i = options.find("avoid_cavities"); + if (i != options.end()) { + opts.avoid_cavities(_bool((*i).second)); + } + return new carve::mesh::MeshSet<3>(points, faceCount, faceIndices, opts); } }; @@ -159,7 +212,7 @@ namespace carve { polylines.back().second.push_back(idx); } - carve::line::PolylineSet *create() const { + carve::line::PolylineSet *create(const Options &options) const { carve::line::PolylineSet *p = new carve::line::PolylineSet(points); for (std::list::const_iterator i = polylines.begin(); @@ -181,7 +234,7 @@ namespace carve { virtual ~PointSetData() { } - carve::point::PointSet *create() const { + carve::point::PointSet *create(const Options &options) const { carve::point::PointSet *p = new carve::point::PointSet(points); return p; } @@ -214,37 +267,37 @@ namespace carve { } template - static inline T *create(Data *d) { + static inline T *create(Data *d, const Options &options = Options()) { return NULL; } }; template<> - inline carve::mesh::MeshSet<3> *Input::create(Data *d) { + inline carve::mesh::MeshSet<3> *Input::create(Data *d, const Options &options) { PolyhedronData *p = dynamic_cast(d); if (p == NULL) return NULL; - return p->createMesh(); + return p->createMesh(options); } template<> - inline carve::poly::Polyhedron *Input::create(Data *d) { + inline carve::poly::Polyhedron *Input::create(Data *d, const Options &options) { PolyhedronData *p = dynamic_cast(d); if (p == NULL) return NULL; - return p->create(); + return p->create(options); } template<> - inline carve::line::PolylineSet *Input::create(Data *d) { + inline carve::line::PolylineSet *Input::create(Data *d, const Options &options) { PolylineSetData *p = dynamic_cast(d); if (p == NULL) return NULL; - return p->create(); + return p->create(options); } template<> - inline carve::point::PointSet *Input::create(Data *d) { + inline carve::point::PointSet *Input::create(Data *d, const Options &options) { PointSetData *p = dynamic_cast(d); if (p == NULL) return NULL; - return p->create(); + return p->create(options); } } diff --git a/extern/carve/include/carve/mesh.hpp b/extern/carve/include/carve/mesh.hpp index d4170e55133..202337b64d3 100644 --- a/extern/carve/include/carve/mesh.hpp +++ b/extern/carve/include/carve/mesh.hpp @@ -464,8 +464,27 @@ namespace carve { + struct MeshOptions { + bool opt_avoid_cavities; + + MeshOptions() : + opt_avoid_cavities(false) { + } + + MeshOptions &avoid_cavities(bool val) { + opt_avoid_cavities = val; + return *this; + } + }; + + + namespace detail { class FaceStitcher { + FaceStitcher(); + FaceStitcher(const FaceStitcher &); + FaceStitcher &operator=(const FaceStitcher &); + typedef Vertex<3> vertex_t; typedef Edge<3> edge_t; typedef Face<3> face_t; @@ -475,6 +494,8 @@ namespace carve { typedef std::unordered_map edge_map_t; typedef std::unordered_map > edge_graph_t; + MeshOptions opts; + edge_map_t edges; edge_map_t complex_edges; @@ -570,6 +591,8 @@ namespace carve { void build(iter_t begin, iter_t end, std::vector *> &meshes); public: + FaceStitcher(const MeshOptions &_opts); + template void create(iter_t begin, iter_t end, std::vector *> &meshes); }; @@ -623,7 +646,7 @@ namespace carve { ~Mesh(); template - static void create(iter_t begin, iter_t end, std::vector *> &meshes); + static void create(iter_t begin, iter_t end, std::vector *> &meshes, const MeshOptions &opts); aabb_t getAABB() const { return aabb_t(faces.begin(), faces.end()); @@ -692,7 +715,7 @@ namespace carve { MeshSet &operator=(const MeshSet &); template - void _init_from_faces(iter_t begin, iter_t end); + void _init_from_faces(iter_t begin, iter_t end, const MeshOptions &opts); public: typedef Vertex vertex_t; @@ -781,13 +804,16 @@ namespace carve { MeshSet(const std::vector &points, size_t n_faces, - const std::vector &face_indices); + const std::vector &face_indices, + const MeshOptions &opts = MeshOptions()); // Construct a mesh set from a set of disconnected faces. Takes // posession of the face pointers. - MeshSet(std::vector &faces); + MeshSet(std::vector &faces, + const MeshOptions &opts = MeshOptions()); - MeshSet(std::list &faces); + MeshSet(std::list &faces, + const MeshOptions &opts = MeshOptions()); MeshSet(std::vector &_vertex_storage, std::vector &_meshes); @@ -817,6 +843,8 @@ namespace carve { void collectVertices(); void canonicalize(); + + void separateMeshes(); }; diff --git a/extern/carve/include/carve/mesh_impl.hpp b/extern/carve/include/carve/mesh_impl.hpp index d55df8c8130..56fb6788b62 100644 --- a/extern/carve/include/carve/mesh_impl.hpp +++ b/extern/carve/include/carve/mesh_impl.hpp @@ -676,7 +676,7 @@ namespace carve { template template - void Mesh::create(iter_t begin, iter_t end, std::vector *> &meshes) { + void Mesh::create(iter_t begin, iter_t end, std::vector *> &meshes, const MeshOptions &opts) { meshes.clear(); } @@ -684,15 +684,15 @@ namespace carve { template<> template - void Mesh<3>::create(iter_t begin, iter_t end, std::vector *> &meshes) { - detail::FaceStitcher().create(begin, end, meshes); + void Mesh<3>::create(iter_t begin, iter_t end, std::vector *> &meshes, const MeshOptions &opts) { + detail::FaceStitcher(opts).create(begin, end, meshes); } template template - void MeshSet::_init_from_faces(iter_t begin, iter_t end) { + void MeshSet::_init_from_faces(iter_t begin, iter_t end, const MeshOptions &opts) { typedef std::unordered_map map_t; map_t vmap; @@ -723,7 +723,7 @@ namespace carve { } while (e != f->edge); } - mesh_t::create(begin, end, meshes); + mesh_t::create(begin, end, meshes, opts); for (size_t i = 0; i < meshes.size(); ++i) { meshes[i]->meshset = this; @@ -735,7 +735,8 @@ namespace carve { template MeshSet::MeshSet(const std::vector::vertex_t::vector_t> &points, size_t n_faces, - const std::vector &face_indices) { + const std::vector &face_indices, + const MeshOptions &opts) { vertex_storage.reserve(points.size()); std::vector faces; faces.reserve(n_faces); @@ -755,7 +756,7 @@ namespace carve { faces.push_back(new face_t(v.begin(), v.end())); } CARVE_ASSERT(p == face_indices.size()); - mesh_t::create(faces.begin(), faces.end(), meshes); + mesh_t::create(faces.begin(), faces.end(), meshes, opts); for (size_t i = 0; i < meshes.size(); ++i) { meshes[i]->meshset = this; @@ -765,15 +766,15 @@ namespace carve { template - MeshSet::MeshSet(std::vector &faces) { - _init_from_faces(faces.begin(), faces.end()); + MeshSet::MeshSet(std::vector &faces, const MeshOptions &opts) { + _init_from_faces(faces.begin(), faces.end(), opts); } template - MeshSet::MeshSet(std::list &faces) { - _init_from_faces(faces.begin(), faces.end()); + MeshSet::MeshSet(std::list &faces, const MeshOptions &opts) { + _init_from_faces(faces.begin(), faces.end(), opts); } @@ -1010,5 +1011,41 @@ namespace carve { vertex_storage.swap(vout); } + + + template + void MeshSet::separateMeshes() { + size_t n; + typedef std::unordered_map, vertex_t *> vmap_t; + vmap_t vmap; + typename vmap_t::iterator vmap_iter; + + for (face_iter i = faceBegin(); i != faceEnd(); ++i) { + face_t *f = *i; + for (typename face_t::edge_iter_t j = f->begin(); j != f->end(); ++j) { + edge_t &e = *j; + vmap[std::make_pair(f->mesh, e.vert)] = e.vert; + } + } + + std::vector vout; + vout.reserve(vmap.size()); + + for (n = 0, vmap_iter = vmap.begin(); vmap_iter != vmap.end(); ++vmap_iter, ++n) { + vout.push_back(*(*vmap_iter).second); + (*vmap_iter).second = & vout.back(); + } + + for (face_iter i = faceBegin(); i != faceEnd(); ++i) { + face_t *f = *i; + for (typename face_t::edge_iter_t j = f->begin(); j != f->end(); ++j) { + edge_t &e = *j; + e.vert = vmap[std::make_pair(f->mesh, e.vert)]; + } + } + + vertex_storage.swap(vout); + } + } } diff --git a/extern/carve/lib/intersect.cpp b/extern/carve/lib/intersect.cpp index b92dbcfe24c..b468e4addc7 100644 --- a/extern/carve/lib/intersect.cpp +++ b/extern/carve/lib/intersect.cpp @@ -1320,8 +1320,8 @@ void carve::csg::CSG::calc(meshset_t *a, } #endif - checkFaceLoopIntegrity(a_face_loops); - checkFaceLoopIntegrity(b_face_loops); + // checkFaceLoopIntegrity(a_face_loops); + // checkFaceLoopIntegrity(b_face_loops); #if defined(CARVE_DEBUG) std::cerr << "classify" << std::endl; diff --git a/extern/carve/lib/intersect_face_division.cpp b/extern/carve/lib/intersect_face_division.cpp index c5d5d8c5152..3b771bc8f3e 100644 --- a/extern/carve/lib/intersect_face_division.cpp +++ b/extern/carve/lib/intersect_face_division.cpp @@ -1110,8 +1110,7 @@ namespace { } // copy up to the end of the path. - if (pos < e1_1) - std::copy(base_loop.begin() + pos, base_loop.begin() + e1_1, std::back_inserter(out)); + std::copy(base_loop.begin() + pos, base_loop.begin() + e1_1, std::back_inserter(out)); CARVE_ASSERT(base_loop[e1_1] == p1.back()); std::copy(p1.rbegin(), p1.rend() - 1, std::back_inserter(out)); diff --git a/extern/carve/lib/mesh.cpp b/extern/carve/lib/mesh.cpp index 55ab893c10a..ae91b385d44 100644 --- a/extern/carve/lib/mesh.cpp +++ b/extern/carve/lib/mesh.cpp @@ -243,15 +243,20 @@ namespace carve { bool FaceStitcher::EdgeOrderData::Cmp::operator()(const EdgeOrderData &a, const EdgeOrderData &b) const { int v = carve::geom3d::compareAngles(edge_dir, base_dir, a.face_dir, b.face_dir); - double da = carve::geom3d::antiClockwiseAngle(base_dir, a.face_dir, edge_dir); - double db = carve::geom3d::antiClockwiseAngle(base_dir, b.face_dir, edge_dir); - int v0 = v; - v = 0; - if (da < db) v = -1; - if (db < da) v = +1; - if (v0 != v) { - std::cerr << "v0= " << v0 << " v= " << v << " da= " << da << " db= " << db << " " << edge_dir << " " << base_dir << " " << a.face_dir << b.face_dir << std::endl; + +#if defined(CARVE_DEBUG) + { + double da = carve::geom3d::antiClockwiseAngle(base_dir, a.face_dir, edge_dir); + double db = carve::geom3d::antiClockwiseAngle(base_dir, b.face_dir, edge_dir); + int v_cmp = 0; + if (da < db) v_cmp = -1; + if (db < da) v_cmp = +1; + if (v_cmp != v) { + std::cerr << "v= " << v << " v_cmp= " << v_cmp << " da= " << da << " db= " << db << " edge_dir=" << edge_dir << " base_dir=" << base_dir << " a=" << a.face_dir << " b=" << b.face_dir << std::endl; + } } +#endif + if (v < 0) return true; if (v == 0) { if (a.is_reversed && !b.is_reversed) return true; @@ -327,9 +332,14 @@ namespace carve { CARVE_ASSERT(erev[0][i]->v2() == erev[j][i]->v2()); } - std::sort(result[i].begin(), - result[i].end(), - EdgeOrderData::Cmp(base->v2()->v - base->v1()->v, result[i][0].face_dir)); + geom::vector<3> sort_dir; + if (opts.opt_avoid_cavities) { + sort_dir = base->v1()->v - base->v2()->v; + } else { + sort_dir = base->v2()->v - base->v1()->v; + } + + std::sort(result[i].begin(), result[i].end(), EdgeOrderData::Cmp(sort_dir, result[i][0].face_dir)); } } @@ -751,11 +761,15 @@ namespace carve { } } } + + FaceStitcher::FaceStitcher(const MeshOptions &_opts) : opts(_opts) { + } } } + // construct a MeshSet from a Polyhedron, maintaining on the // connectivity information in the Polyhedron. mesh::MeshSet<3> *meshFromPolyhedron(const poly::Polyhedron *poly, int manifold_id) { diff --git a/extern/carve/lib/polyhedron.cpp b/extern/carve/lib/polyhedron.cpp index 93e667ffaf7..43d08b81bfd 100644 --- a/extern/carve/lib/polyhedron.cpp +++ b/extern/carve/lib/polyhedron.cpp @@ -233,7 +233,7 @@ namespace carve { } std::vector *> meshes; - mesh::Mesh<3>::create(mesh_faces.begin(), mesh_faces.end(), meshes); + mesh::Mesh<3>::create(mesh_faces.begin(), mesh_faces.end(), meshes, mesh::MeshOptions()); mesh::MeshSet<3> *meshset = new mesh::MeshSet<3>(vertex_storage, meshes); manifold_is_closed.resize(meshset->meshes.size()); diff --git a/extern/carve/patches/series b/extern/carve/patches/series index 585d90659bd..0b1f731805e 100644 --- a/extern/carve/patches/series +++ b/extern/carve/patches/series @@ -1,4 +1,3 @@ -strict_flags.patch includes.patch win32.patch mesh_iterator.patch diff --git a/extern/carve/patches/strict_flags.patch b/extern/carve/patches/strict_flags.patch deleted file mode 100644 index c1046b78c5f..00000000000 --- a/extern/carve/patches/strict_flags.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -r 47dfdaff1dd5 include/carve/csg_triangulator.hpp ---- a/include/carve/csg_triangulator.hpp Thu Jan 12 15:49:04 2012 -0500 -+++ b/include/carve/csg_triangulator.hpp Fri Jan 13 03:13:32 2012 +0600 -@@ -174,6 +174,7 @@ - - double scoreQuad(edge_map_t::iterator i, edge_map_t &edge_map) { - if (!(*i).second.first || !(*i).second.second) return -1; -+ return 0; - } - - carve::mesh::MeshSet<3>::face_t *mergeQuad(edge_map_t::iterator i, edge_map_t &edge_map) { -diff -r 47dfdaff1dd5 lib/selfintersect.cpp ---- a/lib/selfintersect.cpp Thu Jan 12 15:49:04 2012 -0500 -+++ b/lib/selfintersect.cpp Fri Jan 13 03:13:32 2012 +0600 -@@ -465,6 +465,7 @@ - - // returns true if no intersection, based upon edge^a_i and edge^b_j separating axis. - bool sat_edge(const vec3 tri_a[3], const vec3 tri_b[3], unsigned i, unsigned j) { -+ return false; - } - - -- cgit v1.2.3 From 2833994a71c548917341a51f9085149f122ddf53 Mon Sep 17 00:00:00 2001 From: Keir Mierle Date: Mon, 25 Feb 2013 20:00:48 +0000 Subject: Switch motion tracker bundle adjustment to Ceres. Patch originally written by me, then finished by Sergey. Big thanks to Sergey for troopering through and fixing the many issues with my original (not compilable) patch. The Ceres implementation uses 2 parameter blocks for each camera (1 for rotation and 1 for translation), 1 parameter block for common intrinsics (focal length etc) and 1 parameter block for each track (e.g. bundle or 3D point). We turn on some fancy optimizer options to get better performance, in particular: options.preconditioner_type = ceres::SCHUR_JACOBI; options.linear_solver_type = ceres::ITERATIVE_SCHUR; options.use_inner_iterations = true; options.use_nonmonotonic_steps = true; options.max_num_iterations = 100; Special thanks to Sameer Agarwal of Ceres fame for splitting out the SCHUR_JACOBI preconditioner so that it didn't depend on CHOLMOD. Previously we could not use that preconditioner in Blender because CHOLMOD is too large of a dependency for Blender. BundleIntrinsicsLogMessage: - Moved bunch of if(foo) LG << "bar" into this function, to make EuclideanBundleCommonIntrinsics a little bit easier to follow. EuclideanBundle: - Fix RMSE logging. --- .../libmv/libmv/multiview/euclidean_resection.cc | 4 +- extern/libmv/libmv/simple_pipeline/bundle.cc | 437 +++++++++++++-------- 2 files changed, 274 insertions(+), 167 deletions(-) (limited to 'extern') diff --git a/extern/libmv/libmv/multiview/euclidean_resection.cc b/extern/libmv/libmv/multiview/euclidean_resection.cc index 2605bf04622..062c8b9067c 100644 --- a/extern/libmv/libmv/multiview/euclidean_resection.cc +++ b/extern/libmv/libmv/multiview/euclidean_resection.cc @@ -653,8 +653,8 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, // Finally, with all three solutions, select the (R, t) with the best RMSE. VLOG(2) << "RMSE for solution 0: " << rmse(0); - VLOG(2) << "RMSE for solution 1: " << rmse(0); - VLOG(2) << "RMSE for solution 2: " << rmse(0); + VLOG(2) << "RMSE for solution 1: " << rmse(1); + VLOG(2) << "RMSE for solution 2: " << rmse(2); size_t n = 0; if (rmse(1) < rmse(0)) { n = 1; diff --git a/extern/libmv/libmv/simple_pipeline/bundle.cc b/extern/libmv/libmv/simple_pipeline/bundle.cc index d382cd5a4fc..0dd930a5ceb 100644 --- a/extern/libmv/libmv/simple_pipeline/bundle.cc +++ b/extern/libmv/libmv/simple_pipeline/bundle.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 libmv authors. +// Copyright (c) 2011, 2012, 2013 libmv authors. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to @@ -18,10 +18,11 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#define V3DLIB_ENABLE_SUITESPARSE 1 - #include +#include "ceres/ceres.h" +#include "ceres/rotation.h" +#include "libmv/base/scoped_ptr.h" #include "libmv/base/vector.h" #include "libmv/logging/logging.h" #include "libmv/multiview/fundamental.h" @@ -31,218 +32,324 @@ #include "libmv/simple_pipeline/bundle.h" #include "libmv/simple_pipeline/reconstruction.h" #include "libmv/simple_pipeline/tracks.h" -#include "third_party/ssba/Geometry/v3d_cameramatrix.h" -#include "third_party/ssba/Geometry/v3d_metricbundle.h" -#include "third_party/ssba/Math/v3d_linear.h" -#include "third_party/ssba/Math/v3d_linear_utils.h" namespace libmv { -void EuclideanBundle(const Tracks &tracks, - EuclideanReconstruction *reconstruction) { - CameraIntrinsics intrinsics; - EuclideanBundleCommonIntrinsics(tracks, - BUNDLE_NO_INTRINSICS, - reconstruction, - &intrinsics); -} +// The intrinsics need to get combined into a single parameter block; use these +// enums to index instead of numeric constants. +enum { + OFFSET_FOCAL_LENGTH, + OFFSET_PRINCIPAL_POINT_X, + OFFSET_PRINCIPAL_POINT_Y, + OFFSET_K1, + OFFSET_K2, + OFFSET_K3, + OFFSET_P1, + OFFSET_P2, +}; -void EuclideanBundleCommonIntrinsics(const Tracks &tracks, - int bundle_intrinsics, - EuclideanReconstruction *reconstruction, - CameraIntrinsics *intrinsics) { - LG << "Original intrinsics: " << *intrinsics; - vector markers = tracks.AllMarkers(); +namespace { - // "index" in this context is the index that V3D's optimizer will see. The - // V3D index must be dense in that the cameras are numbered 0...n-1, which is - // not the case for the "image" numbering that arises from the tracks - // structure. The complicated mapping is necessary to convert between the two - // representations. - std::map camera_to_index; - std::map point_to_index; - vector index_to_camera; - vector index_to_point; - int num_cameras = 0; - int num_points = 0; - for (int i = 0; i < markers.size(); ++i) { - const Marker &marker = markers[i]; - EuclideanCamera *camera = reconstruction->CameraForImage(marker.image); - EuclideanPoint *point = reconstruction->PointForTrack(marker.track); - if (camera && point) { - if (camera_to_index.find(camera) == camera_to_index.end()) { - camera_to_index[camera] = num_cameras; - index_to_camera.push_back(camera); - num_cameras++; - } - if (point_to_index.find(point) == point_to_index.end()) { - point_to_index[point] = num_points; - index_to_point.push_back(point); - num_points++; - } - } - } +struct OpenCVReprojectionError { + OpenCVReprojectionError(double observed_x, double observed_y) + : observed_x(observed_x), observed_y(observed_y) {} + + template + bool operator()(const T* const intrinsics, + const T* const R, // Rotation 3x3 column-major. + const T* const t, // Translation 3x1. + const T* const X, // Point coordinates 3x1. + T* residuals) const { + // Unpack the intrinsics. + const T& focal_length = intrinsics[OFFSET_FOCAL_LENGTH]; + const T& principal_point_x = intrinsics[OFFSET_PRINCIPAL_POINT_X]; + const T& principal_point_y = intrinsics[OFFSET_PRINCIPAL_POINT_Y]; + const T& k1 = intrinsics[OFFSET_K1]; + const T& k2 = intrinsics[OFFSET_K2]; + const T& k3 = intrinsics[OFFSET_K3]; + const T& p1 = intrinsics[OFFSET_P1]; + const T& p2 = intrinsics[OFFSET_P2]; + + // Compute projective coordinates: x = RX + t. + T x[3]; + x[0] = R[0]*X[0] + R[3]*X[1] + R[6]*X[2] + t[0]; + x[1] = R[1]*X[0] + R[4]*X[1] + R[7]*X[2] + t[1]; + x[2] = R[2]*X[0] + R[5]*X[1] + R[8]*X[2] + t[2]; + + // Compute normalized coordinates: x /= x[2]. + T xn = x[0] / x[2]; + T yn = x[1] / x[2]; + + T predicted_x, predicted_y; + + // EuclideanBundle uses empty intrinsics, which breaks undistortion code; + // so use an implied focal length of 1.0 if the focal length is exactly + // zero. + // TODO(keir): Figure out a better way to do this. + if (focal_length != T(0)) { + // Apply distortion to the normalized points to get (xd, yd). + // TODO(keir): Do early bailouts for zero distortion; these are expensive + // jet operations. + T r2 = xn*xn + yn*yn; + T r4 = r2 * r2; + T r6 = r4 * r2; + T r_coeff = T(1) + k1*r2 + k2*r4 + k3*r6; + T xd = xn * r_coeff + T(2)*p1*xn*yn + p2*(r2 + T(2)*xn*xn); + T yd = yn * r_coeff + T(2)*p2*xn*yn + p1*(r2 + T(2)*yn*yn); - // Convert libmv's K matrix to V3d's K matrix. - V3D::Matrix3x3d v3d_K; - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - v3d_K[i][j] = intrinsics->K()(i, j); + // Apply focal length and principal point to get the final + // image coordinates. + predicted_x = focal_length * xd + principal_point_x; + predicted_y = focal_length * yd + principal_point_y; + } else { + predicted_x = xn; + predicted_y = yn; } + + // The error is the difference between the predicted and observed position. + residuals[0] = predicted_x - T(observed_x); + residuals[1] = predicted_y - T(observed_y); + + return true; } - // Convert libmv's distortion to v3d distortion. - V3D::StdDistortionFunction v3d_distortion; - v3d_distortion.k1 = intrinsics->k1(); - v3d_distortion.k2 = intrinsics->k2(); - v3d_distortion.p1 = intrinsics->p1(); - v3d_distortion.p2 = intrinsics->p2(); - - // Convert libmv's cameras to V3D's cameras. - std::vector v3d_cameras(index_to_camera.size()); - for (int k = 0; k < index_to_camera.size(); ++k) { - V3D::Matrix3x3d R; - V3D::Vector3d t; - - // Libmv's rotation matrix type. - const Mat3 &R_libmv = index_to_camera[k]->R; - const Vec3 &t_libmv = index_to_camera[k]->t; - - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - R[i][j] = R_libmv(i, j); - } - t[i] = t_libmv(i); - } - v3d_cameras[k].setIntrinsic(v3d_K); - v3d_cameras[k].setRotation(R); - v3d_cameras[k].setTranslation(t); + double observed_x; + double observed_y; +}; + +// TODO(keir): Get rid of the parameterization! Ceres will work much faster if +// the rotation block is angle-axis and also the translation is merged into a +// single parameter block. +struct RotationMatrixPlus { + template + bool operator()(const T* R_array, // Rotation 3x3 col-major. + const T* delta, // Angle-axis delta + T* R_plus_delta_array) const { + T angle_axis[3]; + + ceres::RotationMatrixToAngleAxis(R_array, angle_axis); + + angle_axis[0] += delta[0]; + angle_axis[1] += delta[1]; + angle_axis[2] += delta[2]; + + ceres::AngleAxisToRotationMatrix(angle_axis, R_plus_delta_array); + + return true; } - LG << "Number of cameras: " << index_to_camera.size(); - - // Convert libmv's points to V3D's points. - std::vector v3d_points(index_to_point.size()); - for (int i = 0; i < index_to_point.size(); i++) { - v3d_points[i][0] = index_to_point[i]->X(0); - v3d_points[i][1] = index_to_point[i]->X(1); - v3d_points[i][2] = index_to_point[i]->X(2); +}; + +// TODO(sergey): would be nice to have this in Ceres upstream +template +class AutodiffParameterization : public ceres::LocalParameterization { + public: + AutodiffParameterization(const PlusFunctor &plus_functor) + : plus_functor_(plus_functor) {} + + virtual ~AutodiffParameterization() {} + + virtual bool Plus(const double* x, + const double* delta, + double* x_plus_delta) const { + return plus_functor_(x, delta, x_plus_delta); } - LG << "Number of points: " << index_to_point.size(); - // Convert libmv's measurements to v3d measurements. - int num_residuals = 0; - std::vector v3d_measurements; - std::vector v3d_camera_for_measurement; - std::vector v3d_point_for_measurement; - for (int i = 0; i < markers.size(); ++i) { - EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image); - EuclideanPoint *point = reconstruction->PointForTrack(markers[i].track); - if (!camera || !point) { - continue; - } - V3D::Vector2d v3d_point; - v3d_point[0] = markers[i].x; - v3d_point[1] = markers[i].y; - v3d_measurements.push_back(v3d_point); - v3d_camera_for_measurement.push_back(camera_to_index[camera]); - v3d_point_for_measurement.push_back(point_to_index[point]); - num_residuals++; + virtual bool ComputeJacobian(const double* x, double* jacobian) const { + double zero_delta[kLocalSize] = { 0.0 }; + double x_plus_delta[kGlobalSize]; + const double* parameters[2] = { x, zero_delta }; + double* jacobians_array[2] = { NULL, jacobian }; + + Plus(x, zero_delta, x_plus_delta); + + return ceres::internal::AutoDiff + ::Differentiate(plus_functor_, + parameters, + kGlobalSize, + x_plus_delta, + jacobians_array); + + return true; } - LG << "Number of residuals: " << num_residuals; - - // Convert from libmv's specification for which intrinsics to bundle to V3D's. - int v3d_bundle_intrinsics; + + virtual int GlobalSize() const { return kGlobalSize; } + virtual int LocalSize() const { return kLocalSize; } + + private: + const PlusFunctor &plus_functor_; +}; + +void BundleIntrinsicsLogMessage(int bundle_intrinsics) { if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) { LG << "Bundling only camera positions."; - v3d_bundle_intrinsics = V3D::FULL_BUNDLE_METRIC; } else if (bundle_intrinsics == BUNDLE_FOCAL_LENGTH) { LG << "Bundling f."; - v3d_bundle_intrinsics = V3D::FULL_BUNDLE_FOCAL_LENGTH; } else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH | BUNDLE_PRINCIPAL_POINT)) { LG << "Bundling f, px, py."; - v3d_bundle_intrinsics = V3D::FULL_BUNDLE_FOCAL_LENGTH_PP; } else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH | BUNDLE_PRINCIPAL_POINT | BUNDLE_RADIAL)) { LG << "Bundling f, px, py, k1, k2."; - v3d_bundle_intrinsics = V3D::FULL_BUNDLE_RADIAL; } else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH | BUNDLE_PRINCIPAL_POINT | BUNDLE_RADIAL | BUNDLE_TANGENTIAL)) { LG << "Bundling f, px, py, k1, k2, p1, p2."; - v3d_bundle_intrinsics = V3D::FULL_BUNDLE_RADIAL_TANGENTIAL; } else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH | BUNDLE_RADIAL | BUNDLE_TANGENTIAL)) { LG << "Bundling f, px, py, k1, k2, p1, p2."; - v3d_bundle_intrinsics = V3D::FULL_BUNDLE_RADIAL_TANGENTIAL; } else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH | BUNDLE_RADIAL)) { LG << "Bundling f, k1, k2."; - v3d_bundle_intrinsics = V3D::FULL_BUNDLE_FOCAL_AND_RADIAL; } else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH | BUNDLE_RADIAL_K1)) { LG << "Bundling f, k1."; - v3d_bundle_intrinsics = V3D::FULL_BUNDLE_FOCAL_AND_RADIAL_K1; } else { LOG(FATAL) << "Unsupported bundle combination."; } +} - // Ignore any outliers; assume supervised tracking. - double v3d_inlier_threshold = 500000.0; - - // Finally, run the bundle adjustment. - V3D::CommonInternalsMetricBundleOptimizer opt(v3d_bundle_intrinsics, - v3d_inlier_threshold, - v3d_K, - v3d_distortion, - v3d_cameras, - v3d_points, - v3d_measurements, - v3d_camera_for_measurement, - v3d_point_for_measurement); - opt.maxIterations = 500; - opt.minimize(); - if (opt.status == V3D::LEVENBERG_OPTIMIZER_TIMEOUT) { - LG << "Bundle status: Timed out."; - } else if (opt.status == V3D::LEVENBERG_OPTIMIZER_SMALL_UPDATE) { - LG << "Bundle status: Small update."; - } else if (opt.status == V3D::LEVENBERG_OPTIMIZER_CONVERGED) { - LG << "Bundle status: Converged."; - } +} // namespace - // Convert V3D's K matrix back to libmv's K matrix. - Mat3 K; - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - K(i, j) = v3d_K[i][j]; +void EuclideanBundle(const Tracks &tracks, + EuclideanReconstruction *reconstruction) { + CameraIntrinsics intrinsics; + EuclideanBundleCommonIntrinsics(tracks, + BUNDLE_NO_INTRINSICS, + reconstruction, + &intrinsics); +} + +void EuclideanBundleCommonIntrinsics(const Tracks &tracks, + int bundle_intrinsics, + EuclideanReconstruction *reconstruction, + CameraIntrinsics *intrinsics) { + LG << "Original intrinsics: " << *intrinsics; + vector markers = tracks.AllMarkers(); + + ceres::Problem::Options problem_options; + problem_options.local_parameterization_ownership = + ceres::DO_NOT_TAKE_OWNERSHIP; + + ceres::Problem problem(problem_options); + + // Residual blocks with 10 parameters are unwieldly with Ceres, so pack the + // intrinsics into a single block and rely on local parameterizations to + // control which intrinsics are allowed to vary. + double ceres_intrinsics[8]; + ceres_intrinsics[OFFSET_FOCAL_LENGTH] = intrinsics->focal_length(); + ceres_intrinsics[OFFSET_PRINCIPAL_POINT_X] = intrinsics->principal_point_x(); + ceres_intrinsics[OFFSET_PRINCIPAL_POINT_Y] = intrinsics->principal_point_y(); + ceres_intrinsics[OFFSET_K1] = intrinsics->k1(); + ceres_intrinsics[OFFSET_K2] = intrinsics->k2(); + ceres_intrinsics[OFFSET_K3] = intrinsics->k3(); + ceres_intrinsics[OFFSET_P1] = intrinsics->p1(); + ceres_intrinsics[OFFSET_P2] = intrinsics->p2(); + + RotationMatrixPlus rotation_matrix_plus; + AutodiffParameterization + rotation_parameterization(rotation_matrix_plus); + + int num_residuals = 0; + for (int i = 0; i < markers.size(); ++i) { + const Marker &marker = markers[i]; + EuclideanCamera *camera = reconstruction->CameraForImage(marker.image); + EuclideanPoint *point = reconstruction->PointForTrack(marker.track); + if (!camera || !point) { + continue; } + + problem.AddResidualBlock(new ceres::AutoDiffCostFunction< + OpenCVReprojectionError, 2, 8, 9 /* 3 */, 3, 3>( + new OpenCVReprojectionError( + marker.x, + marker.y)), + NULL, + ceres_intrinsics, + &camera->R(0, 0), + &camera->t(0), + &point->X(0)); + + // It's fine if the parameterization for one camera is set repeatedly. + problem.SetParameterization(&camera->R(0, 0), + &rotation_parameterization); + + num_residuals++; } - intrinsics->SetK(K); - - // Convert V3D's distortion back to libmv's distortion. - intrinsics->SetRadialDistortion(v3d_distortion.k1, v3d_distortion.k2, 0.0); - intrinsics->SetTangentialDistortion(v3d_distortion.p1, v3d_distortion.p2); - - // Convert V3D's cameras back to libmv's cameras. - for (int k = 0; k < num_cameras; k++) { - V3D::Matrix3x4d const Rt = v3d_cameras[k].getOrientation(); - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - index_to_camera[k]->R(i, j) = Rt[i][j]; - } - index_to_camera[k]->t(i) = Rt[i][3]; - } + LG << "Number of residuals: " << num_residuals; + + if(!num_residuals) { + LG << "Skipping running minimizer with zero residuals"; + return; } - // Convert V3D's points back to libmv's points. - for (int k = 0; k < num_points; k++) { - for (int i = 0; i < 3; ++i) { - index_to_point[k]->X(i) = v3d_points[k][i]; + BundleIntrinsicsLogMessage(bundle_intrinsics); + + scoped_ptr + subset_parameterization(NULL); + + if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) { + // No camera intrinsics are refining, + // set the whole parameter block as constant for best performance + problem.SetParameterBlockConstant(ceres_intrinsics); + } else { + // Set intrinsics not being bundles as constant + + std::vector constant_intrinsics; +#define MAYBE_SET_CONSTANT(bundle_enum, offset) \ + if (!(bundle_intrinsics & bundle_enum)) { \ + constant_intrinsics.push_back(offset); \ } + MAYBE_SET_CONSTANT(BUNDLE_FOCAL_LENGTH, OFFSET_FOCAL_LENGTH); + MAYBE_SET_CONSTANT(BUNDLE_PRINCIPAL_POINT, OFFSET_PRINCIPAL_POINT_X); + MAYBE_SET_CONSTANT(BUNDLE_PRINCIPAL_POINT, OFFSET_PRINCIPAL_POINT_Y); + MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K1, OFFSET_K1); + MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K2, OFFSET_K2); + MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P1, OFFSET_P1); + MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P2, OFFSET_P2); +#undef MAYBE_SET_CONSTANT + + // Always set K3 constant, it's not used at the moment. + constant_intrinsics.push_back(OFFSET_K3); + + subset_parameterization.reset( + new ceres::SubsetParameterization(8, constant_intrinsics)); + + problem.SetParameterization(ceres_intrinsics, subset_parameterization.get()); + } + + ceres::Solver::Options options; + options.use_nonmonotonic_steps = true; + options.preconditioner_type = ceres::SCHUR_JACOBI; + options.linear_solver_type = ceres::ITERATIVE_SCHUR; + options.use_inner_iterations = true; + options.max_num_iterations = 100; + + ceres::Solver::Summary summary; + ceres::Solve(options, &problem, &summary); + + LG << "Final report:\n" << summary.FullReport(); + + // Copy intrinsics back. + if (bundle_intrinsics != BUNDLE_NO_INTRINSICS) { + intrinsics->SetFocalLength(ceres_intrinsics[OFFSET_FOCAL_LENGTH], + ceres_intrinsics[OFFSET_FOCAL_LENGTH]); + + intrinsics->SetPrincipalPoint(ceres_intrinsics[OFFSET_PRINCIPAL_POINT_X], + ceres_intrinsics[OFFSET_PRINCIPAL_POINT_Y]); + + intrinsics->SetRadialDistortion(ceres_intrinsics[OFFSET_K1], + ceres_intrinsics[OFFSET_K2], + ceres_intrinsics[OFFSET_K3]); + + intrinsics->SetTangentialDistortion(ceres_intrinsics[OFFSET_P1], + ceres_intrinsics[OFFSET_P2]); } + LG << "Final intrinsics: " << *intrinsics; } -- cgit v1.2.3 From b7af3207cca5b28b5b901258412bdfab00b41fca Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 25 Feb 2013 20:15:42 +0000 Subject: Bye-bye, SSBA! With new bundle adjustment based on Ceres we don't need SSBA library anymore. This also means we don't need ldl library and libmv is no longer depends on colamd as well. --- extern/libmv/CMakeLists.txt | 14 - extern/libmv/SConscript | 5 - extern/libmv/bundle.sh | 4 - extern/libmv/libmv-capi.cpp | 5 - extern/libmv/third_party/ldl/CMakeLists.txt | 5 - extern/libmv/third_party/ldl/Doc/ChangeLog | 39 - extern/libmv/third_party/ldl/Doc/lesser.txt | 504 ----------- extern/libmv/third_party/ldl/Include/ldl.h | 104 --- extern/libmv/third_party/ldl/README.libmv | 10 - extern/libmv/third_party/ldl/README.txt | 136 --- extern/libmv/third_party/ldl/Source/ldl.c | 507 ----------- extern/libmv/third_party/ssba/COPYING.TXT | 165 ---- .../third_party/ssba/Geometry/v3d_cameramatrix.h | 204 ----- .../third_party/ssba/Geometry/v3d_distortion.h | 97 --- .../third_party/ssba/Geometry/v3d_metricbundle.cpp | 405 --------- .../third_party/ssba/Geometry/v3d_metricbundle.h | 352 -------- extern/libmv/third_party/ssba/Math/v3d_linear.h | 923 -------------------- .../libmv/third_party/ssba/Math/v3d_linear_utils.h | 391 --------- .../third_party/ssba/Math/v3d_mathutilities.h | 59 -- .../third_party/ssba/Math/v3d_optimization.cpp | 955 --------------------- .../libmv/third_party/ssba/Math/v3d_optimization.h | 273 ------ extern/libmv/third_party/ssba/README.TXT | 92 -- extern/libmv/third_party/ssba/README.libmv | 23 - 23 files changed, 5272 deletions(-) delete mode 100644 extern/libmv/third_party/ldl/CMakeLists.txt delete mode 100644 extern/libmv/third_party/ldl/Doc/ChangeLog delete mode 100644 extern/libmv/third_party/ldl/Doc/lesser.txt delete mode 100644 extern/libmv/third_party/ldl/Include/ldl.h delete mode 100644 extern/libmv/third_party/ldl/README.libmv delete mode 100644 extern/libmv/third_party/ldl/README.txt delete mode 100644 extern/libmv/third_party/ldl/Source/ldl.c delete mode 100644 extern/libmv/third_party/ssba/COPYING.TXT delete mode 100644 extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h delete mode 100644 extern/libmv/third_party/ssba/Geometry/v3d_distortion.h delete mode 100644 extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp delete mode 100644 extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h delete mode 100644 extern/libmv/third_party/ssba/Math/v3d_linear.h delete mode 100644 extern/libmv/third_party/ssba/Math/v3d_linear_utils.h delete mode 100644 extern/libmv/third_party/ssba/Math/v3d_mathutilities.h delete mode 100644 extern/libmv/third_party/ssba/Math/v3d_optimization.cpp delete mode 100644 extern/libmv/third_party/ssba/Math/v3d_optimization.h delete mode 100644 extern/libmv/third_party/ssba/README.TXT delete mode 100644 extern/libmv/third_party/ssba/README.libmv (limited to 'extern') diff --git a/extern/libmv/CMakeLists.txt b/extern/libmv/CMakeLists.txt index 0fc90fdd9b9..200e20de91b 100644 --- a/extern/libmv/CMakeLists.txt +++ b/extern/libmv/CMakeLists.txt @@ -28,14 +28,11 @@ set(INC . - ../colamd/Include third_party/ceres/include ) set(INC_SYS ../Eigen3 - third_party/ssba - third_party/ldl/Include ${PNG_INCLUDE_DIR} ${ZLIB_INCLUDE_DIRS} ) @@ -83,9 +80,6 @@ set(SRC third_party/gflags/gflags.cc third_party/gflags/gflags_completions.cc third_party/gflags/gflags_reporting.cc - third_party/ldl/Source/ldl.c - third_party/ssba/Geometry/v3d_metricbundle.cpp - third_party/ssba/Math/v3d_optimization.cpp libmv-capi.h libmv/base/id_generator.h @@ -143,16 +137,8 @@ set(SRC third_party/gflags/gflags/gflags.h third_party/gflags/mutex.h third_party/gflags/util.h - third_party/ldl/Include/ldl.h third_party/msinttypes/inttypes.h third_party/msinttypes/stdint.h - third_party/ssba/Geometry/v3d_cameramatrix.h - third_party/ssba/Geometry/v3d_distortion.h - third_party/ssba/Geometry/v3d_metricbundle.h - third_party/ssba/Math/v3d_linear.h - third_party/ssba/Math/v3d_linear_utils.h - third_party/ssba/Math/v3d_mathutilities.h - third_party/ssba/Math/v3d_optimization.h ) if(WIN32) diff --git a/extern/libmv/SConscript b/extern/libmv/SConscript index 8fd8c566e4d..a503730926d 100644 --- a/extern/libmv/SConscript +++ b/extern/libmv/SConscript @@ -22,9 +22,6 @@ src += env.Glob('libmv/simple_pipeline/*.cc') src += env.Glob('libmv/tracking/*.cc') src += env.Glob('third_party/fast/*.c') src += env.Glob('third_party/gflags/*.cc') -src += env.Glob('third_party/ldl/Source/*.c') -src += env.Glob('third_party/ssba/Geometry/*.cpp') -src += env.Glob('third_party/ssba/Math/*.cpp') incs = '. ../Eigen3 third_party/ceres/include' incs += ' ' + env['BF_PNG_INC'] @@ -41,8 +38,6 @@ else: src += env.Glob("third_party/glog/src/*.cc") incs += ' ./third_party/glog/src' -incs += ' ./third_party/ssba ./third_party/ldl/Include ../colamd/Include' - env.BlenderLib ( libname = 'extern_libmv', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137] ) SConscript(['third_party/SConscript']) diff --git a/extern/libmv/bundle.sh b/extern/libmv/bundle.sh index 53487cf020e..6b26bd95157 100755 --- a/extern/libmv/bundle.sh +++ b/extern/libmv/bundle.sh @@ -130,8 +130,6 @@ set(INC set(INC_SYS ../Eigen3 - third_party/ssba - third_party/ldl/Include \${PNG_INCLUDE_DIR} \${ZLIB_INCLUDE_DIRS} ) @@ -241,8 +239,6 @@ else: src += env.Glob("third_party/glog/src/*.cc") incs += ' ./third_party/glog/src' -incs += ' ./third_party/ssba ./third_party/ldl/Include ../colamd/Include' - env.BlenderLib ( libname = 'extern_libmv', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137] ) SConscript(['third_party/SConscript']) diff --git a/extern/libmv/libmv-capi.cpp b/extern/libmv/libmv-capi.cpp index 4f00d7d68b4..945bc0c879e 100644 --- a/extern/libmv/libmv-capi.cpp +++ b/extern/libmv/libmv-capi.cpp @@ -38,8 +38,6 @@ #include "glog/logging.h" #include "libmv/logging/logging.h" -#include "Math/v3d_optimization.h" - #include "libmv/numeric/numeric.h" #include "libmv/tracking/esm_region_tracker.h" @@ -96,7 +94,6 @@ void libmv_initLogging(const char *argv0) google::SetCommandLineOption("v", "0"); google::SetCommandLineOption("stderrthreshold", "7"); google::SetCommandLineOption("minloglevel", "7"); - V3D::optimizerVerbosenessLevel = 0; } void libmv_startDebugLogging(void) @@ -105,7 +102,6 @@ void libmv_startDebugLogging(void) google::SetCommandLineOption("v", "2"); google::SetCommandLineOption("stderrthreshold", "1"); google::SetCommandLineOption("minloglevel", "0"); - V3D::optimizerVerbosenessLevel = 1; } void libmv_setLoggingVerbosity(int verbosity) @@ -114,7 +110,6 @@ void libmv_setLoggingVerbosity(int verbosity) snprintf(val, sizeof(val), "%d", verbosity); google::SetCommandLineOption("v", val); - V3D::optimizerVerbosenessLevel = verbosity; } /* ************ Utility ************ */ diff --git a/extern/libmv/third_party/ldl/CMakeLists.txt b/extern/libmv/third_party/ldl/CMakeLists.txt deleted file mode 100644 index db2d40e2612..00000000000 --- a/extern/libmv/third_party/ldl/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -include_directories(../ufconfig) -include_directories(Include) -add_library(ldl Source/ldl.c) - -LIBMV_INSTALL_THIRD_PARTY_LIB(ldl) diff --git a/extern/libmv/third_party/ldl/Doc/ChangeLog b/extern/libmv/third_party/ldl/Doc/ChangeLog deleted file mode 100644 index 48c322d3e77..00000000000 --- a/extern/libmv/third_party/ldl/Doc/ChangeLog +++ /dev/null @@ -1,39 +0,0 @@ -May 31, 2007: version 2.0.0 - - * C-callable 64-bit version added - - * ported to 64-bit MATLAB - - * subdirectories added (Source/, Include/, Lib/, Demo/, Doc/, MATLAB/) - -Dec 12, 2006: version 1.3.4 - - * minor MATLAB cleanup - -Sept 11, 2006: version 1.3.1 - - * The ldl m-file renamed to ldlsparse, to avoid name conflict with the - new MATLAB ldl function (in MATLAB 7.3). - -Apr 30, 2006: version 1.3 - - * requires AMD v2.0. ldlmain.c demo program modified, since AMD can now - handle jumbled matrices. Minor change to Makefile. - -Aug 30, 2005: - - * Makefile changed to use ../UFconfig/UFconfig.mk. License changed to - GNU LGPL. - -July 4, 2005: - - * user guide added. Since no changes to the code were made, - the version number (1.1) and code release date (Apr 22, 2005) - were left unchanged. - -Apr. 22, 2005: LDL v1.1 released. - - * No real changes were made. The code was revised so - that each routine fits on a single page in the documentation. - -Dec 31, 2003: LDL v1.0 released. diff --git a/extern/libmv/third_party/ldl/Doc/lesser.txt b/extern/libmv/third_party/ldl/Doc/lesser.txt deleted file mode 100644 index 8add30ad590..00000000000 --- a/extern/libmv/third_party/ldl/Doc/lesser.txt +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/extern/libmv/third_party/ldl/Include/ldl.h b/extern/libmv/third_party/ldl/Include/ldl.h deleted file mode 100644 index 5840be322f7..00000000000 --- a/extern/libmv/third_party/ldl/Include/ldl.h +++ /dev/null @@ -1,104 +0,0 @@ -/* ========================================================================== */ -/* === ldl.h: include file for the LDL package ============================= */ -/* ========================================================================== */ - -/* LDL Copyright (c) Timothy A Davis, - * University of Florida. All Rights Reserved. See README for the License. - */ - -#include "UFconfig.h" - -#ifdef LDL_LONG -#define LDL_int UF_long -#define LDL_ID UF_long_id - -#define LDL_symbolic ldl_l_symbolic -#define LDL_numeric ldl_l_numeric -#define LDL_lsolve ldl_l_lsolve -#define LDL_dsolve ldl_l_dsolve -#define LDL_ltsolve ldl_l_ltsolve -#define LDL_perm ldl_l_perm -#define LDL_permt ldl_l_permt -#define LDL_valid_perm ldl_l_valid_perm -#define LDL_valid_matrix ldl_l_valid_matrix - -#else -#define LDL_int int -#define LDL_ID "%d" - -#define LDL_symbolic ldl_symbolic -#define LDL_numeric ldl_numeric -#define LDL_lsolve ldl_lsolve -#define LDL_dsolve ldl_dsolve -#define LDL_ltsolve ldl_ltsolve -#define LDL_perm ldl_perm -#define LDL_permt ldl_permt -#define LDL_valid_perm ldl_valid_perm -#define LDL_valid_matrix ldl_valid_matrix - -#endif - -/* ========================================================================== */ -/* === int version ========================================================== */ -/* ========================================================================== */ - -void ldl_symbolic (int n, int Ap [ ], int Ai [ ], int Lp [ ], - int Parent [ ], int Lnz [ ], int Flag [ ], int P [ ], int Pinv [ ]) ; - -int ldl_numeric (int n, int Ap [ ], int Ai [ ], double Ax [ ], - int Lp [ ], int Parent [ ], int Lnz [ ], int Li [ ], double Lx [ ], - double D [ ], double Y [ ], int Pattern [ ], int Flag [ ], - int P [ ], int Pinv [ ]) ; - -void ldl_lsolve (int n, double X [ ], int Lp [ ], int Li [ ], - double Lx [ ]) ; - -void ldl_dsolve (int n, double X [ ], double D [ ]) ; - -void ldl_ltsolve (int n, double X [ ], int Lp [ ], int Li [ ], - double Lx [ ]) ; - -void ldl_perm (int n, double X [ ], double B [ ], int P [ ]) ; -void ldl_permt (int n, double X [ ], double B [ ], int P [ ]) ; - -int ldl_valid_perm (int n, int P [ ], int Flag [ ]) ; -int ldl_valid_matrix ( int n, int Ap [ ], int Ai [ ]) ; - -/* ========================================================================== */ -/* === long version ========================================================= */ -/* ========================================================================== */ - -void ldl_l_symbolic (UF_long n, UF_long Ap [ ], UF_long Ai [ ], UF_long Lp [ ], - UF_long Parent [ ], UF_long Lnz [ ], UF_long Flag [ ], UF_long P [ ], - UF_long Pinv [ ]) ; - -UF_long ldl_l_numeric (UF_long n, UF_long Ap [ ], UF_long Ai [ ], double Ax [ ], - UF_long Lp [ ], UF_long Parent [ ], UF_long Lnz [ ], UF_long Li [ ], - double Lx [ ], double D [ ], double Y [ ], UF_long Pattern [ ], - UF_long Flag [ ], UF_long P [ ], UF_long Pinv [ ]) ; - -void ldl_l_lsolve (UF_long n, double X [ ], UF_long Lp [ ], UF_long Li [ ], - double Lx [ ]) ; - -void ldl_l_dsolve (UF_long n, double X [ ], double D [ ]) ; - -void ldl_l_ltsolve (UF_long n, double X [ ], UF_long Lp [ ], UF_long Li [ ], - double Lx [ ]) ; - -void ldl_l_perm (UF_long n, double X [ ], double B [ ], UF_long P [ ]) ; -void ldl_l_permt (UF_long n, double X [ ], double B [ ], UF_long P [ ]) ; - -UF_long ldl_l_valid_perm (UF_long n, UF_long P [ ], UF_long Flag [ ]) ; -UF_long ldl_l_valid_matrix ( UF_long n, UF_long Ap [ ], UF_long Ai [ ]) ; - -/* ========================================================================== */ -/* === LDL version ========================================================== */ -/* ========================================================================== */ - -#define LDL_DATE "Nov 1, 2007" -#define LDL_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) -#define LDL_MAIN_VERSION 2 -#define LDL_SUB_VERSION 0 -#define LDL_SUBSUB_VERSION 1 -#define LDL_VERSION LDL_VERSION_CODE(LDL_MAIN_VERSION,LDL_SUB_VERSION) - diff --git a/extern/libmv/third_party/ldl/README.libmv b/extern/libmv/third_party/ldl/README.libmv deleted file mode 100644 index 64ece48a390..00000000000 --- a/extern/libmv/third_party/ldl/README.libmv +++ /dev/null @@ -1,10 +0,0 @@ -Project: LDL -URL: http://www.cise.ufl.edu/research/sparse/ldl/ -License: LGPL2.1 -Upstream version: 2.0.1 (despite the ChangeLog saying 2.0.0) - -Local modifications: - - * Deleted everything except ldl.c, ldl.h, the license, the ChangeLog, and the - README. - diff --git a/extern/libmv/third_party/ldl/README.txt b/extern/libmv/third_party/ldl/README.txt deleted file mode 100644 index 7be8dd1f001..00000000000 --- a/extern/libmv/third_party/ldl/README.txt +++ /dev/null @@ -1,136 +0,0 @@ -LDL Version 2.0: a sparse LDL' factorization and solve package. - Written in C, with both a C and MATLAB mexFunction interface. - -These routines are not terrifically fast (they do not use dense matrix kernels), -but the code is very short and concise. The purpose is to illustrate the -algorithms in a very concise and readable manner, primarily for educational -purposes. Although the code is very concise, this package is slightly faster -than the built-in sparse Cholesky factorization in MATLAB 6.5 (chol), when -using the same input permutation. - -Requires UFconfig, in the ../UFconfig directory relative to this directory. - -Quick start (Unix, or Windows with Cygwin): - - To compile, test, and install LDL, you may wish to first obtain a copy of - AMD v2.0 from http://www.cise.ufl.edu/research/sparse, and place it in the - ../AMD directory, relative to this directory. Next, type "make", which - will compile the LDL library and three demo main programs (one of which - requires AMD). It will also compile the LDL MATLAB mexFunction (if you - have MATLAB). Typing "make clean" will remove non-essential files. - AMD v2.0 or later is required. Its use is optional. - -Quick start (for MATLAB users); - - To compile, test, and install the LDL mexFunctions (ldlsparse and - ldlsymbol), start MATLAB in this directory and type ldl_install. - This works on any system supported by MATLAB. - --------------------------------------------------------------------------------- - -LDL Copyright (c) 2005 by Timothy A. Davis. All Rights Reserved. - -LDL License: - - Your use or distribution of LDL or any modified version of - LDL implies that you agree to this License. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 - USA - - Permission is hereby granted to use or copy this program under the - terms of the GNU LGPL, provided that the Copyright, this License, - and the Availability of the original version is retained on all copies. - User documentation of any code that uses this code or any modified - version of this code must cite the Copyright, this License, the - Availability note, and "Used by permission." Permission to modify - the code and to distribute modified code is granted, provided the - Copyright, this License, and the Availability note are retained, - and a notice that the code was modified is included. - -Availability: - - http://www.cise.ufl.edu/research/sparse/ldl - -Acknowledgements: - - This work was supported by the National Science Foundation, under - grant CCR-0203270. - - Portions of this work were done while on sabbatical at Stanford University - and Lawrence Berkeley National Laboratory (with funding from the SciDAC - program). I would like to thank Gene Golub, Esmond Ng, and Horst Simon - for making this sabbatical possible. I would like to thank Pete Stewart - for his comments on a draft of this software and paper. - --------------------------------------------------------------------------------- -Files and directories in this distribution: --------------------------------------------------------------------------------- - - Documentation, and compiling: - - README.txt this file - Makefile for compiling LDL - ChangeLog changes since V1.0 (Dec 31, 2003) - License license - lesser.txt the GNU LGPL license - - ldl_userguide.pdf user guide in PDF - ldl_userguide.ps user guide in postscript - ldl_userguide.tex user guide in Latex - ldl.bib bibliography for user guide - - The LDL library itself: - - ldl.c the C-callable routines - ldl.h include file for any code that calls LDL - - A simple C main program that demonstrates how to use LDL: - - ldlsimple.c a stand-alone C program, uses the basic features of LDL - ldlsimple.out output of ldlsimple - - ldllsimple.c long integer version of ldlsimple.c - - Demo C program, for testing LDL and providing an example of its use - - ldlmain.c a stand-alone C main program that uses and tests LDL - Matrix a directory containing matrices used by ldlmain.c - ldlmain.out output of ldlmain - ldlamd.out output of ldlamd (ldlmain.c compiled with AMD) - ldllamd.out output of ldllamd (ldlmain.c compiled with AMD, long) - - MATLAB-related, not required for use in a regular C program - - Contents.m a list of the MATLAB-callable routines - ldl.m MATLAB help file for the LDL mexFunction - ldldemo.m MATLAB demo of how to use the LDL mexFunction - ldldemo.out diary output of ldldemo - ldltest.m to test the LDL mexFunction - ldltest.out diary output of ldltest - ldlmex.c the LDL mexFunction for MATLAB - ldlrow.m the numerical algorithm that LDL is based on - ldlmain2.m compiles and runs ldlmain.c as a MATLAB mexFunction - ldlmain2.out output of ldlmain2.m - ldlsymbolmex.c symbolic factorization using LDL (see SYMBFACT, ETREE) - ldlsymbol.m help file for the LDLSYMBOL mexFunction - - ldl_install.m compile, install, and test LDL functions - ldl_make.m compile LDL (ldlsparse and ldlsymbol) - - ldlsparse.m help for ldlsparse - -See ldl.c for a description of how to use the code from a C program. Type -"help ldl" in MATLAB for information on how to use LDL in a MATLAB program. diff --git a/extern/libmv/third_party/ldl/Source/ldl.c b/extern/libmv/third_party/ldl/Source/ldl.c deleted file mode 100644 index a9b35c846ef..00000000000 --- a/extern/libmv/third_party/ldl/Source/ldl.c +++ /dev/null @@ -1,507 +0,0 @@ -/* ========================================================================== */ -/* === ldl.c: sparse LDL' factorization and solve package =================== */ -/* ========================================================================== */ - -/* LDL: a simple set of routines for sparse LDL' factorization. These routines - * are not terrifically fast (they do not use dense matrix kernels), but the - * code is very short. The purpose is to illustrate the algorithms in a very - * concise manner, primarily for educational purposes. Although the code is - * very concise, this package is slightly faster than the built-in sparse - * Cholesky factorization in MATLAB 7.0 (chol), when using the same input - * permutation. - * - * The routines compute the LDL' factorization of a real sparse symmetric - * matrix A (or PAP' if a permutation P is supplied), and solve upper - * and lower triangular systems with the resulting L and D factors. If A is - * positive definite then the factorization will be accurate. A can be - * indefinite (with negative values on the diagonal D), but in this case no - * guarantee of accuracy is provided, since no numeric pivoting is performed. - * - * The n-by-n sparse matrix A is in compressed-column form. The nonzero values - * in column j are stored in Ax [Ap [j] ... Ap [j+1]-1], with corresponding row - * indices in Ai [Ap [j] ... Ap [j+1]-1]. Ap [0] = 0 is required, and thus - * nz = Ap [n] is the number of nonzeros in A. Ap is an int array of size n+1. - * The int array Ai and the double array Ax are of size nz. This data structure - * is identical to the one used by MATLAB, except for the following - * generalizations. The row indices in each column of A need not be in any - * particular order, although they must be in the range 0 to n-1. Duplicate - * entries can be present; any duplicates are summed. That is, if row index i - * appears twice in a column j, then the value of A (i,j) is the sum of the two - * entries. The data structure used here for the input matrix A is more - * flexible than MATLAB's, which requires sorted columns with no duplicate - * entries. - * - * Only the diagonal and upper triangular part of A (or PAP' if a permutation - * P is provided) is accessed. The lower triangular parts of the matrix A or - * PAP' can be present, but they are ignored. - * - * The optional input permutation is provided as an array P of length n. If - * P [k] = j, the row and column j of A is the kth row and column of PAP'. - * If P is present then the factorization is LDL' = PAP' or L*D*L' = A(P,P) in - * 0-based MATLAB notation. If P is not present (a null pointer) then no - * permutation is performed, and the factorization is LDL' = A. - * - * The lower triangular matrix L is stored in the same compressed-column - * form (an int Lp array of size n+1, an int Li array of size Lp [n], and a - * double array Lx of the same size as Li). It has a unit diagonal, which is - * not stored. The row indices in each column of L are always returned in - * ascending order, with no duplicate entries. This format is compatible with - * MATLAB, except that it would be more convenient for MATLAB to include the - * unit diagonal of L. Doing so here would add additional complexity to the - * code, and is thus omitted in the interest of keeping this code short and - * readable. - * - * The elimination tree is held in the Parent [0..n-1] array. It is normally - * not required by the user, but it is required by ldl_numeric. The diagonal - * matrix D is held as an array D [0..n-1] of size n. - * - * -------------------- - * C-callable routines: - * -------------------- - * - * ldl_symbolic: Given the pattern of A, computes the Lp and Parent arrays - * required by ldl_numeric. Takes time proportional to the number of - * nonzeros in L. Computes the inverse Pinv of P if P is provided. - * Also returns Lnz, the count of nonzeros in each column of L below - * the diagonal (this is not required by ldl_numeric). - * ldl_numeric: Given the pattern and numerical values of A, the Lp array, - * the Parent array, and P and Pinv if applicable, computes the - * pattern and numerical values of L and D. - * ldl_lsolve: Solves Lx=b for a dense vector b. - * ldl_dsolve: Solves Dx=b for a dense vector b. - * ldl_ltsolve: Solves L'x=b for a dense vector b. - * ldl_perm: Computes x=Pb for a dense vector b. - * ldl_permt: Computes x=P'b for a dense vector b. - * ldl_valid_perm: checks the validity of a permutation vector - * ldl_valid_matrix: checks the validity of the sparse matrix A - * - * ---------------------------- - * Limitations of this package: - * ---------------------------- - * - * In the interest of keeping this code simple and readable, ldl_symbolic and - * ldl_numeric assume their inputs are valid. You can check your own inputs - * prior to calling these routines with the ldl_valid_perm and ldl_valid_matrix - * routines. Except for the two ldl_valid_* routines, no routine checks to see - * if the array arguments are present (non-NULL). Like all C routines, no - * routine can determine if the arrays are long enough and don't overlap. - * - * The ldl_numeric does check the numerical factorization, however. It returns - * n if the factorization is successful. If D (k,k) is zero, then k is - * returned, and L is only partially computed. - * - * No pivoting to control fill-in is performed, which is often critical for - * obtaining good performance. I recommend that you compute the permutation P - * using AMD or SYMAMD (approximate minimum degree ordering routines), or an - * appropriate graph-partitioning based ordering. See the ldldemo.m routine for - * an example in MATLAB, and the ldlmain.c stand-alone C program for examples of - * how to find P. Routines for manipulating compressed-column matrices are - * available in UMFPACK. AMD, SYMAMD, UMFPACK, and this LDL package are all - * available at http://www.cise.ufl.edu/research/sparse. - * - * ------------------------- - * Possible simplifications: - * ------------------------- - * - * These routines could be made even simpler with a few additional assumptions. - * If no input permutation were performed, the caller would have to permute the - * matrix first, but the computation of Pinv, and the use of P and Pinv could be - * removed. If only the diagonal and upper triangular part of A or PAP' are - * present, then the tests in the "if (i < k)" statement in ldl_symbolic and - * "if (i <= k)" in ldl_numeric, are always true, and could be removed (i can - * equal k in ldl_symbolic, but then the body of the if statement would - * correctly do no work since Flag [k] == k). If we could assume that no - * duplicate entries are present, then the statement Y [i] += Ax [p] could be - * replaced with Y [i] = Ax [p] in ldl_numeric. - * - * -------------------------- - * Description of the method: - * -------------------------- - * - * LDL computes the symbolic factorization by finding the pattern of L one row - * at a time. It does this based on the following theory. Consider a sparse - * system Lx=b, where L, x, and b, are all sparse, and where L comes from a - * Cholesky (or LDL') factorization. The elimination tree (etree) of L is - * defined as follows. The parent of node j is the smallest k > j such that - * L (k,j) is nonzero. Node j has no parent if column j of L is completely zero - * below the diagonal (j is a root of the etree in this case). The nonzero - * pattern of x is the union of the paths from each node i to the root, for - * each nonzero b (i). To compute the numerical solution to Lx=b, we can - * traverse the columns of L corresponding to nonzero values of x. This - * traversal does not need to be done in the order 0 to n-1. It can be done in - * any "topological" order, such that x (i) is computed before x (j) if i is a - * descendant of j in the elimination tree. - * - * The row-form of the LDL' factorization is shown in the MATLAB function - * ldlrow.m in this LDL package. Note that row k of L is found via a sparse - * triangular solve of L (1:k-1, 1:k-1) \ A (1:k-1, k), to use 1-based MATLAB - * notation. Thus, we can start with the nonzero pattern of the kth column of - * A (above the diagonal), follow the paths up to the root of the etree of the - * (k-1)-by-(k-1) leading submatrix of L, and obtain the pattern of the kth row - * of L. Note that we only need the leading (k-1)-by-(k-1) submatrix of L to - * do this. The elimination tree can be constructed as we go. - * - * The symbolic factorization does the same thing, except that it discards the - * pattern of L as it is computed. It simply counts the number of nonzeros in - * each column of L and then constructs the Lp index array when it's done. The - * symbolic factorization does not need to do this in topological order. - * Compare ldl_symbolic with the first part of ldl_numeric, and note that the - * while (len > 0) loop is not present in ldl_symbolic. - * - * LDL Version 1.3, Copyright (c) 2006 by Timothy A Davis, - * University of Florida. All Rights Reserved. Developed while on sabbatical - * at Stanford University and Lawrence Berkeley National Laboratory. Refer to - * the README file for the License. Available at - * http://www.cise.ufl.edu/research/sparse. - */ - -#include "ldl.h" - -/* ========================================================================== */ -/* === ldl_symbolic ========================================================= */ -/* ========================================================================== */ - -/* The input to this routine is a sparse matrix A, stored in column form, and - * an optional permutation P. The output is the elimination tree - * and the number of nonzeros in each column of L. Parent [i] = k if k is the - * parent of i in the tree. The Parent array is required by ldl_numeric. - * Lnz [k] gives the number of nonzeros in the kth column of L, excluding the - * diagonal. - * - * One workspace vector (Flag) of size n is required. - * - * If P is NULL, then it is ignored. The factorization will be LDL' = A. - * Pinv is not computed. In this case, neither P nor Pinv are required by - * ldl_numeric. - * - * If P is not NULL, then it is assumed to be a valid permutation. If - * row and column j of A is the kth pivot, the P [k] = j. The factorization - * will be LDL' = PAP', or A (p,p) in MATLAB notation. The inverse permutation - * Pinv is computed, where Pinv [j] = k if P [k] = j. In this case, both P - * and Pinv are required as inputs to ldl_numeric. - * - * The floating-point operation count of the subsequent call to ldl_numeric - * is not returned, but could be computed after ldl_symbolic is done. It is - * the sum of (Lnz [k]) * (Lnz [k] + 2) for k = 0 to n-1. - */ - -void LDL_symbolic -( - LDL_int n, /* A and L are n-by-n, where n >= 0 */ - LDL_int Ap [ ], /* input of size n+1, not modified */ - LDL_int Ai [ ], /* input of size nz=Ap[n], not modified */ - LDL_int Lp [ ], /* output of size n+1, not defined on input */ - LDL_int Parent [ ], /* output of size n, not defined on input */ - LDL_int Lnz [ ], /* output of size n, not defined on input */ - LDL_int Flag [ ], /* workspace of size n, not defn. on input or output */ - LDL_int P [ ], /* optional input of size n */ - LDL_int Pinv [ ] /* optional output of size n (used if P is not NULL) */ -) -{ - LDL_int i, k, p, kk, p2 ; - if (P) - { - /* If P is present then compute Pinv, the inverse of P */ - for (k = 0 ; k < n ; k++) - { - Pinv [P [k]] = k ; - } - } - for (k = 0 ; k < n ; k++) - { - /* L(k,:) pattern: all nodes reachable in etree from nz in A(0:k-1,k) */ - Parent [k] = -1 ; /* parent of k is not yet known */ - Flag [k] = k ; /* mark node k as visited */ - Lnz [k] = 0 ; /* count of nonzeros in column k of L */ - kk = (P) ? (P [k]) : (k) ; /* kth original, or permuted, column */ - p2 = Ap [kk+1] ; - for (p = Ap [kk] ; p < p2 ; p++) - { - /* A (i,k) is nonzero (original or permuted A) */ - i = (Pinv) ? (Pinv [Ai [p]]) : (Ai [p]) ; - if (i < k) - { - /* follow path from i to root of etree, stop at flagged node */ - for ( ; Flag [i] != k ; i = Parent [i]) - { - /* find parent of i if not yet determined */ - if (Parent [i] == -1) Parent [i] = k ; - Lnz [i]++ ; /* L (k,i) is nonzero */ - Flag [i] = k ; /* mark i as visited */ - } - } - } - } - /* construct Lp index array from Lnz column counts */ - Lp [0] = 0 ; - for (k = 0 ; k < n ; k++) - { - Lp [k+1] = Lp [k] + Lnz [k] ; - } -} - - -/* ========================================================================== */ -/* === ldl_numeric ========================================================== */ -/* ========================================================================== */ - -/* Given a sparse matrix A (the arguments n, Ap, Ai, and Ax) and its symbolic - * analysis (Lp and Parent, and optionally P and Pinv), compute the numeric LDL' - * factorization of A or PAP'. The outputs of this routine are arguments Li, - * Lx, and D. It also requires three size-n workspaces (Y, Pattern, and Flag). - */ - -LDL_int LDL_numeric /* returns n if successful, k if D (k,k) is zero */ -( - LDL_int n, /* A and L are n-by-n, where n >= 0 */ - LDL_int Ap [ ], /* input of size n+1, not modified */ - LDL_int Ai [ ], /* input of size nz=Ap[n], not modified */ - double Ax [ ], /* input of size nz=Ap[n], not modified */ - LDL_int Lp [ ], /* input of size n+1, not modified */ - LDL_int Parent [ ], /* input of size n, not modified */ - LDL_int Lnz [ ], /* output of size n, not defn. on input */ - LDL_int Li [ ], /* output of size lnz=Lp[n], not defined on input */ - double Lx [ ], /* output of size lnz=Lp[n], not defined on input */ - double D [ ], /* output of size n, not defined on input */ - double Y [ ], /* workspace of size n, not defn. on input or output */ - LDL_int Pattern [ ],/* workspace of size n, not defn. on input or output */ - LDL_int Flag [ ], /* workspace of size n, not defn. on input or output */ - LDL_int P [ ], /* optional input of size n */ - LDL_int Pinv [ ] /* optional input of size n */ -) -{ - double yi, l_ki ; - LDL_int i, k, p, kk, p2, len, top ; - for (k = 0 ; k < n ; k++) - { - /* compute nonzero Pattern of kth row of L, in topological order */ - Y [k] = 0.0 ; /* Y(0:k) is now all zero */ - top = n ; /* stack for pattern is empty */ - Flag [k] = k ; /* mark node k as visited */ - Lnz [k] = 0 ; /* count of nonzeros in column k of L */ - kk = (P) ? (P [k]) : (k) ; /* kth original, or permuted, column */ - p2 = Ap [kk+1] ; - for (p = Ap [kk] ; p < p2 ; p++) - { - i = (Pinv) ? (Pinv [Ai [p]]) : (Ai [p]) ; /* get A(i,k) */ - if (i <= k) - { - Y [i] += Ax [p] ; /* scatter A(i,k) into Y (sum duplicates) */ - for (len = 0 ; Flag [i] != k ; i = Parent [i]) - { - Pattern [len++] = i ; /* L(k,i) is nonzero */ - Flag [i] = k ; /* mark i as visited */ - } - while (len > 0) Pattern [--top] = Pattern [--len] ; - } - } - /* compute numerical values kth row of L (a sparse triangular solve) */ - D [k] = Y [k] ; /* get D(k,k) and clear Y(k) */ - Y [k] = 0.0 ; - for ( ; top < n ; top++) - { - i = Pattern [top] ; /* Pattern [top:n-1] is pattern of L(:,k) */ - yi = Y [i] ; /* get and clear Y(i) */ - Y [i] = 0.0 ; - p2 = Lp [i] + Lnz [i] ; - for (p = Lp [i] ; p < p2 ; p++) - { - Y [Li [p]] -= Lx [p] * yi ; - } - l_ki = yi / D [i] ; /* the nonzero entry L(k,i) */ - D [k] -= l_ki * yi ; - Li [p] = k ; /* store L(k,i) in column form of L */ - Lx [p] = l_ki ; - Lnz [i]++ ; /* increment count of nonzeros in col i */ - } - if (D [k] == 0.0) return (k) ; /* failure, D(k,k) is zero */ - } - return (n) ; /* success, diagonal of D is all nonzero */ -} - - -/* ========================================================================== */ -/* === ldl_lsolve: solve Lx=b ============================================== */ -/* ========================================================================== */ - -void LDL_lsolve -( - LDL_int n, /* L is n-by-n, where n >= 0 */ - double X [ ], /* size n. right-hand-side on input, soln. on output */ - LDL_int Lp [ ], /* input of size n+1, not modified */ - LDL_int Li [ ], /* input of size lnz=Lp[n], not modified */ - double Lx [ ] /* input of size lnz=Lp[n], not modified */ -) -{ - LDL_int j, p, p2 ; - for (j = 0 ; j < n ; j++) - { - p2 = Lp [j+1] ; - for (p = Lp [j] ; p < p2 ; p++) - { - X [Li [p]] -= Lx [p] * X [j] ; - } - } -} - - -/* ========================================================================== */ -/* === ldl_dsolve: solve Dx=b ============================================== */ -/* ========================================================================== */ - -void LDL_dsolve -( - LDL_int n, /* D is n-by-n, where n >= 0 */ - double X [ ], /* size n. right-hand-side on input, soln. on output */ - double D [ ] /* input of size n, not modified */ -) -{ - LDL_int j ; - for (j = 0 ; j < n ; j++) - { - X [j] /= D [j] ; - } -} - - -/* ========================================================================== */ -/* === ldl_ltsolve: solve L'x=b ============================================ */ -/* ========================================================================== */ - -void LDL_ltsolve -( - LDL_int n, /* L is n-by-n, where n >= 0 */ - double X [ ], /* size n. right-hand-side on input, soln. on output */ - LDL_int Lp [ ], /* input of size n+1, not modified */ - LDL_int Li [ ], /* input of size lnz=Lp[n], not modified */ - double Lx [ ] /* input of size lnz=Lp[n], not modified */ -) -{ - int j, p, p2 ; - for (j = n-1 ; j >= 0 ; j--) - { - p2 = Lp [j+1] ; - for (p = Lp [j] ; p < p2 ; p++) - { - X [j] -= Lx [p] * X [Li [p]] ; - } - } -} - - -/* ========================================================================== */ -/* === ldl_perm: permute a vector, x=Pb ===================================== */ -/* ========================================================================== */ - -void LDL_perm -( - LDL_int n, /* size of X, B, and P */ - double X [ ], /* output of size n. */ - double B [ ], /* input of size n. */ - LDL_int P [ ] /* input permutation array of size n. */ -) -{ - LDL_int j ; - for (j = 0 ; j < n ; j++) - { - X [j] = B [P [j]] ; - } -} - - -/* ========================================================================== */ -/* === ldl_permt: permute a vector, x=P'b =================================== */ -/* ========================================================================== */ - -void LDL_permt -( - LDL_int n, /* size of X, B, and P */ - double X [ ], /* output of size n. */ - double B [ ], /* input of size n. */ - LDL_int P [ ] /* input permutation array of size n. */ -) -{ - LDL_int j ; - for (j = 0 ; j < n ; j++) - { - X [P [j]] = B [j] ; - } -} - - -/* ========================================================================== */ -/* === ldl_valid_perm: check if a permutation vector is valid =============== */ -/* ========================================================================== */ - -LDL_int LDL_valid_perm /* returns 1 if valid, 0 otherwise */ -( - LDL_int n, - LDL_int P [ ], /* input of size n, a permutation of 0:n-1 */ - LDL_int Flag [ ] /* workspace of size n */ -) -{ - LDL_int j, k ; - if (n < 0 || !Flag) - { - return (0) ; /* n must be >= 0, and Flag must be present */ - } - if (!P) - { - return (1) ; /* If NULL, P is assumed to be the identity perm. */ - } - for (j = 0 ; j < n ; j++) - { - Flag [j] = 0 ; /* clear the Flag array */ - } - for (k = 0 ; k < n ; k++) - { - j = P [k] ; - if (j < 0 || j >= n || Flag [j] != 0) - { - return (0) ; /* P is not valid */ - } - Flag [j] = 1 ; - } - return (1) ; /* P is valid */ -} - - -/* ========================================================================== */ -/* === ldl_valid_matrix: check if a sparse matrix is valid ================== */ -/* ========================================================================== */ - -/* This routine checks to see if a sparse matrix A is valid for input to - * ldl_symbolic and ldl_numeric. It returns 1 if the matrix is valid, 0 - * otherwise. A is in sparse column form. The numerical values in column j - * are stored in Ax [Ap [j] ... Ap [j+1]-1], with row indices in - * Ai [Ap [j] ... Ap [j+1]-1]. The Ax array is not checked. - */ - -LDL_int LDL_valid_matrix -( - LDL_int n, - LDL_int Ap [ ], - LDL_int Ai [ ] -) -{ - LDL_int j, p ; - if (n < 0 || !Ap || !Ai || Ap [0] != 0) - { - return (0) ; /* n must be >= 0, and Ap and Ai must be present */ - } - for (j = 0 ; j < n ; j++) - { - if (Ap [j] > Ap [j+1]) - { - return (0) ; /* Ap must be monotonically nondecreasing */ - } - } - for (p = 0 ; p < Ap [n] ; p++) - { - if (Ai [p] < 0 || Ai [p] >= n) - { - return (0) ; /* row indices must be in the range 0 to n-1 */ - } - } - return (1) ; /* matrix is valid */ -} diff --git a/extern/libmv/third_party/ssba/COPYING.TXT b/extern/libmv/third_party/ssba/COPYING.TXT deleted file mode 100644 index fc8a5de7edf..00000000000 --- a/extern/libmv/third_party/ssba/COPYING.TXT +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h b/extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h deleted file mode 100644 index 448ae9714e5..00000000000 --- a/extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h +++ /dev/null @@ -1,204 +0,0 @@ -// -*- C++ -*- -/* -Copyright (c) 2008 University of North Carolina at Chapel Hill - -This file is part of SSBA (Simple Sparse Bundle Adjustment). - -SSBA is free software: you can redistribute it and/or modify it under the -terms of the GNU Lesser General Public License as published by the Free -Software Foundation, either version 3 of the License, or (at your option) any -later version. - -SSBA is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. - -You should have received a copy of the GNU Lesser General Public License along -with SSBA. If not, see . -*/ - -#ifndef V3D_CAMERA_MATRIX_H -#define V3D_CAMERA_MATRIX_H - -#include "Math/v3d_linear.h" -#include "Geometry/v3d_distortion.h" - -namespace V3D -{ - - struct CameraMatrix - { - CameraMatrix() - { - makeIdentityMatrix(_K); - makeIdentityMatrix(_R); - makeZeroVector(_T); - this->updateCachedValues(true, true); - } - - CameraMatrix(double f, double cx, double cy) - { - makeIdentityMatrix(_K); - _K[0][0] = f; - _K[1][1] = f; - _K[0][2] = cx; - _K[1][2] = cy; - makeIdentityMatrix(_R); - makeZeroVector(_T); - this->updateCachedValues(true, true); - } - - CameraMatrix(Matrix3x3d const& K, - Matrix3x3d const& R, - Vector3d const& T) - : _K(K), _R(R), _T(T) - { - this->updateCachedValues(true, true); - } - - void setIntrinsic(Matrix3x3d const& K) { _K = K; this->updateCachedValues(true, false); } - void setRotation(Matrix3x3d const& R) { _R = R; this->updateCachedValues(false, true); } - void setTranslation(Vector3d const& T) { _T = T; this->updateCachedValues(false, true); } - - template - void setOrientation(Mat const& RT) - { - _R[0][0] = RT[0][0]; _R[0][1] = RT[0][1]; _R[0][2] = RT[0][2]; - _R[1][0] = RT[1][0]; _R[1][1] = RT[1][1]; _R[1][2] = RT[1][2]; - _R[2][0] = RT[2][0]; _R[2][1] = RT[2][1]; _R[2][2] = RT[2][2]; - _T[0] = RT[0][3]; _T[1] = RT[1][3]; _T[2] = RT[2][3]; - this->updateCachedValues(false, true); - } - - Matrix3x3d const& getIntrinsic() const { return _K; } - Matrix3x3d const& getRotation() const { return _R; } - Vector3d const& getTranslation() const { return _T; } - - Matrix3x4d getOrientation() const - { - Matrix3x4d RT; - RT[0][0] = _R[0][0]; RT[0][1] = _R[0][1]; RT[0][2] = _R[0][2]; - RT[1][0] = _R[1][0]; RT[1][1] = _R[1][1]; RT[1][2] = _R[1][2]; - RT[2][0] = _R[2][0]; RT[2][1] = _R[2][1]; RT[2][2] = _R[2][2]; - RT[0][3] = _T[0]; RT[1][3] = _T[1]; RT[2][3] = _T[2]; - return RT; - } - - Matrix3x4d getProjection() const - { - Matrix3x4d const RT = this->getOrientation(); - return _K * RT; - } - - double getFocalLength() const { return _K[0][0]; } - double getAspectRatio() const { return _K[1][1] / _K[0][0]; } - - Vector2d getPrincipalPoint() const - { - Vector2d pp; - pp[0] = _K[0][2]; - pp[1] = _K[1][2]; - return pp; - } - - Vector2d projectPoint(Vector3d const& X) const - { - Vector3d q = _K*(_R*X + _T); - Vector2d res; - res[0] = q[0]/q[2]; res[1] = q[1]/q[2]; - return res; - } - - template - Vector2d projectPoint(Distortion const& distortion, Vector3d const& X) const - { - Vector3d XX = _R*X + _T; - Vector2d p; - p[0] = XX[0] / XX[2]; - p[1] = XX[1] / XX[2]; - p = distortion(p); - - Vector2d res; - res[0] = _K[0][0] * p[0] + _K[0][1] * p[1] + _K[0][2]; - res[1] = _K[1][1] * p[1] + _K[1][2]; - return res; - } - - Vector3d unprojectPixel(Vector2d const &p, double depth = 1) const - { - Vector3d pp; - pp[0] = p[0]; pp[1] = p[1]; pp[2] = 1.0; - Vector3d ray = _invK * pp; - ray[0] *= depth/ray[2]; - ray[1] *= depth/ray[2]; - ray[2] = depth; - ray = _Rt * ray; - return _center + ray; - } - - Vector3d transformPointIntoCameraSpace(Vector3d const& p) const - { - return _R*p + _T; - } - - Vector3d transformPointFromCameraSpace(Vector3d const& p) const - { - return _Rt*(p-_T); - } - - Vector3d transformDirectionFromCameraSpace(Vector3d const& dir) const - { - return _Rt*dir; - } - - Vector3d const& cameraCenter() const - { - return _center; - } - - Vector3d opticalAxis() const - { - return this->transformDirectionFromCameraSpace(makeVector3(0.0, 0.0, 1.0)); - } - - Vector3d upVector() const - { - return this->transformDirectionFromCameraSpace(makeVector3(0.0, 1.0, 0.0)); - } - - Vector3d rightVector() const - { - return this->transformDirectionFromCameraSpace(makeVector3(1.0, 0.0, 0.0)); - } - - Vector3d getRay(Vector2d const& p) const - { - Vector3d pp = makeVector3(p[0], p[1], 1.0); - Vector3d ray = _invK * pp; - ray = _Rt * ray; - normalizeVector(ray); - return ray; - } - - protected: - void updateCachedValues(bool intrinsic, bool orientation) - { - if (intrinsic) _invK = invertedMatrix(_K); - - if (orientation) - { - makeTransposedMatrix(_R, _Rt); - _center = _Rt * (-1.0 * _T); - } - } - - Matrix3x3d _K, _R; - Vector3d _T; - Matrix3x3d _invK, _Rt; - Vector3d _center; - }; // end struct CameraMatrix - -} // end namespace V3D - -#endif diff --git a/extern/libmv/third_party/ssba/Geometry/v3d_distortion.h b/extern/libmv/third_party/ssba/Geometry/v3d_distortion.h deleted file mode 100644 index d0816558314..00000000000 --- a/extern/libmv/third_party/ssba/Geometry/v3d_distortion.h +++ /dev/null @@ -1,97 +0,0 @@ -// -*- C++ -*- -/* -Copyright (c) 2008 University of North Carolina at Chapel Hill - -This file is part of SSBA (Simple Sparse Bundle Adjustment). - -SSBA is free software: you can redistribute it and/or modify it under the -terms of the GNU Lesser General Public License as published by the Free -Software Foundation, either version 3 of the License, or (at your option) any -later version. - -SSBA is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. - -You should have received a copy of the GNU Lesser General Public License along -with SSBA. If not, see . -*/ - -#ifndef V3D_DISTORTION_H -#define V3D_DISTORTION_H - -#include "Math/v3d_linear.h" -#include "Math/v3d_linear_utils.h" - -namespace V3D -{ - - struct StdDistortionFunction - { - double k1, k2, p1, p2; - - StdDistortionFunction() - : k1(0), k2(0), p1(0), p2(0) - { } - - Vector2d operator()(Vector2d const& xu) const - { - double const r2 = xu[0]*xu[0] + xu[1]*xu[1]; - double const r4 = r2*r2; - double const kr = 1 + k1*r2 + k2*r4; - - Vector2d xd; - xd[0] = kr * xu[0] + 2*p1*xu[0]*xu[1] + p2*(r2 + 2*xu[0]*xu[0]); - xd[1] = kr * xu[1] + 2*p2*xu[0]*xu[1] + p1*(r2 + 2*xu[1]*xu[1]); - return xd; - } - - Matrix2x2d derivativeWrtRadialParameters(Vector2d const& xu) const - { - double const r2 = xu[0]*xu[0] + xu[1]*xu[1]; - double const r4 = r2*r2; - //double const kr = 1 + k1*r2 + k2*r4; - - Matrix2x2d deriv; - - deriv[0][0] = xu[0] * r2; // d xd/d k1 - deriv[0][1] = xu[0] * r4; // d xd/d k2 - deriv[1][0] = xu[1] * r2; // d yd/d k1 - deriv[1][1] = xu[1] * r4; // d yd/d k2 - return deriv; - } - - Matrix2x2d derivativeWrtTangentialParameters(Vector2d const& xu) const - { - double const r2 = xu[0]*xu[0] + xu[1]*xu[1]; - //double const r4 = r2*r2; - //double const kr = 1 + k1*r2 + k2*r4; - - Matrix2x2d deriv; - deriv[0][0] = 2*xu[0]*xu[1]; // d xd/d p1 - deriv[0][1] = r2 + 2*xu[0]*xu[0]; // d xd/d p2 - deriv[1][0] = r2 + 2*xu[1]*xu[1]; // d yd/d p1 - deriv[1][1] = deriv[0][0]; // d yd/d p2 - return deriv; - } - - Matrix2x2d derivativeWrtUndistortedPoint(Vector2d const& xu) const - { - double const r2 = xu[0]*xu[0] + xu[1]*xu[1]; - double const r4 = r2*r2; - double const kr = 1 + k1*r2 + k2*r4; - double const dkr = 2*k1 + 4*k2*r2; - - Matrix2x2d deriv; - deriv[0][0] = kr + xu[0] * xu[0] * dkr + 2*p1*xu[1] + 6*p2*xu[0]; // d xd/d xu - deriv[0][1] = xu[0] * xu[1] * dkr + 2*p1*xu[0] + 2*p2*xu[1]; // d xd/d yu - deriv[1][0] = deriv[0][1]; // d yd/d xu - deriv[1][1] = kr + xu[1] * xu[1] * dkr + 6*p1*xu[1] + 2*p2*xu[0]; // d yd/d yu - return deriv; - } - }; // end struct StdDistortionFunction - -} // end namespace V3D - -#endif diff --git a/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp b/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp deleted file mode 100644 index 7eb2dfac5d9..00000000000 --- a/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp +++ /dev/null @@ -1,405 +0,0 @@ -/* -Copyright (c) 2008 University of North Carolina at Chapel Hill - -This file is part of SSBA (Simple Sparse Bundle Adjustment). - -SSBA is free software: you can redistribute it and/or modify it under the -terms of the GNU Lesser General Public License as published by the Free -Software Foundation, either version 3 of the License, or (at your option) any -later version. - -SSBA is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. - -You should have received a copy of the GNU Lesser General Public License along -with SSBA. If not, see . -*/ - -#include "Geometry/v3d_metricbundle.h" - -#if defined(V3DLIB_ENABLE_SUITESPARSE) - -namespace -{ - - typedef V3D::InlineMatrix Matrix2x4d; - typedef V3D::InlineMatrix Matrix4x2d; - typedef V3D::InlineMatrix Matrix2x6d; - -} // end namespace <> - -namespace V3D -{ - - void - MetricBundleOptimizerBase::updateParametersA(VectorArray const& deltaAi) - { - Vector3d T, omega; - Matrix3x3d R0, dR; - - for (int i = _nNonvaryingA; i < _nParametersA; ++i) - { - T = _cams[i].getTranslation(); - T[0] += deltaAi[i][0]; - T[1] += deltaAi[i][1]; - T[2] += deltaAi[i][2]; - _cams[i].setTranslation(T); - - // Create incremental rotation using Rodriguez formula. - R0 = _cams[i].getRotation(); - omega[0] = deltaAi[i][3]; - omega[1] = deltaAi[i][4]; - omega[2] = deltaAi[i][5]; - createRotationMatrixRodriguez(omega, dR); - _cams[i].setRotation(dR * R0); - } // end for (i) - } // end MetricBundleOptimizerBase::updateParametersA() - - void - MetricBundleOptimizerBase::updateParametersB(VectorArray const& deltaBj) - { - for (int j = _nNonvaryingB; j < _nParametersB; ++j) - { - _Xs[j][0] += deltaBj[j][0]; - _Xs[j][1] += deltaBj[j][1]; - _Xs[j][2] += deltaBj[j][2]; - } - } // end MetricBundleOptimizerBase::updateParametersB() - - void - MetricBundleOptimizerBase::poseDerivatives(int i, int j, Vector3d& XX, - Matrix3x6d& d_dRT, Matrix3x3d& d_dX) const - { - XX = _cams[i].transformPointIntoCameraSpace(_Xs[j]); - - // See Frank Dellaerts bundle adjustment tutorial. - // d(dR * R0 * X + t)/d omega = -[R0 * X]_x - Matrix3x3d J; - makeCrossProductMatrix(XX - _cams[i].getTranslation(), J); - scaleMatrixIP(-1.0, J); - - // Now the transformation from world coords into camera space is xx = Rx + T - // Hence the derivative of x wrt. T is just the identity matrix. - makeIdentityMatrix(d_dRT); - copyMatrixSlice(J, 0, 0, 3, 3, d_dRT, 0, 3); - - // The derivative of Rx+T wrt x is just R. - copyMatrix(_cams[i].getRotation(), d_dX); - } // end MetricBundleOptimizerBase::poseDerivatives() - - -//---------------------------------------------------------------------- - - void - StdMetricBundleOptimizer::fillJacobians(Matrix& Ak, - Matrix& Bk, - Matrix& Ck, - int i, int j, int k) - { - Vector3d XX; - Matrix3x6d d_dRT; - Matrix3x3d d_dX; - this->poseDerivatives(i, j, XX, d_dRT, d_dX); - - double const f = _cams[i].getFocalLength(); - double const ar = _cams[i].getAspectRatio(); - - Matrix2x3d dp_dX; - double const bx = f / (XX[2] * XX[2]); - double const by = ar * bx; - dp_dX[0][0] = bx * XX[2]; dp_dX[0][1] = 0; dp_dX[0][2] = -bx * XX[0]; - dp_dX[1][0] = 0; dp_dX[1][1] = by * XX[2]; dp_dX[1][2] = -by * XX[1]; - - multiply_A_B(dp_dX, d_dRT, Ak); - multiply_A_B(dp_dX, d_dX, Bk); - } // end StdMetricBundleOptimizer::fillJacobians() - - //---------------------------------------------------------------------- - - void - CommonInternalsMetricBundleOptimizer::fillJacobians(Matrix& Ak, - Matrix& Bk, - Matrix& Ck, - int i, int j, int k) - { - double const focalLength = _K[0][0]; - - Vector3d XX; - Matrix3x6d dXX_dRT; - Matrix3x3d dXX_dX; - this->poseDerivatives(i, j, XX, dXX_dRT, dXX_dX); - - Vector2d xu; // undistorted image point - xu[0] = XX[0] / XX[2]; - xu[1] = XX[1] / XX[2]; - - Vector2d const xd = _distortion(xu); // distorted image point - - Matrix2x2d dp_dxd; - dp_dxd[0][0] = focalLength; dp_dxd[0][1] = 0; - dp_dxd[1][0] = 0; dp_dxd[1][1] = _cachedAspectRatio * focalLength; - - { - // First, lets do the derivative wrt the structure and motion parameters. - Matrix2x3d dxu_dXX; - dxu_dXX[0][0] = 1.0f / XX[2]; dxu_dXX[0][1] = 0; dxu_dXX[0][2] = -XX[0]/(XX[2]*XX[2]); - dxu_dXX[1][0] = 0; dxu_dXX[1][1] = 1.0f / XX[2]; dxu_dXX[1][2] = -XX[1]/(XX[2]*XX[2]); - - Matrix2x2d dxd_dxu = _distortion.derivativeWrtUndistortedPoint(xu); - - Matrix2x2d dp_dxu = dp_dxd * dxd_dxu; - Matrix2x3d dp_dXX = dp_dxu * dxu_dXX; - - multiply_A_B(dp_dXX, dXX_dRT, Ak); - multiply_A_B(dp_dXX, dXX_dX, Bk); - } // end scope - - switch (_mode) - { - case FULL_BUNDLE_FOCAL_AND_RADIAL_K1: - { - // Focal length. - Ck[0][0] = xd[0]; - Ck[1][0] = xd[1]; - - // For radial, k1 only. - Matrix2x2d dxd_dk1k2 = _distortion.derivativeWrtRadialParameters(xu); - Matrix2x2d d_dk1k2 = dp_dxd * dxd_dk1k2; - Ck[0][1] = d_dk1k2[0][0]; - Ck[1][1] = d_dk1k2[1][0]; - break; - } - case FULL_BUNDLE_FOCAL_AND_RADIAL: - { - // Focal length. - Ck[0][0] = xd[0]; - Ck[1][0] = xd[1]; - - // Radial k1 and k2. - Matrix2x2d dxd_dk1k2 = _distortion.derivativeWrtRadialParameters(xu); - Matrix2x2d d_dk1k2 = dp_dxd * dxd_dk1k2; - copyMatrixSlice(d_dk1k2, 0, 0, 2, 2, Ck, 0, 1); - break; - } - case FULL_BUNDLE_RADIAL_TANGENTIAL: - { - Matrix2x2d dxd_dp1p2 = _distortion.derivativeWrtTangentialParameters(xu); - Matrix2x2d d_dp1p2 = dp_dxd * dxd_dp1p2; - copyMatrixSlice(d_dp1p2, 0, 0, 2, 2, Ck, 0, 5); - // No break here! - } - case FULL_BUNDLE_RADIAL: - { - Matrix2x2d dxd_dk1k2 = _distortion.derivativeWrtRadialParameters(xu); - Matrix2x2d d_dk1k2 = dp_dxd * dxd_dk1k2; - copyMatrixSlice(d_dk1k2, 0, 0, 2, 2, Ck, 0, 3); - // No break here! - } - case FULL_BUNDLE_FOCAL_LENGTH_PP: - { - Ck[0][1] = 1; Ck[0][2] = 0; - Ck[1][1] = 0; Ck[1][2] = 1; - // No break here! - } - case FULL_BUNDLE_FOCAL_LENGTH: - { - Ck[0][0] = xd[0]; - Ck[1][0] = xd[1]; - } - case FULL_BUNDLE_METRIC: - { - } - } // end switch - } // end CommonInternalsMetricBundleOptimizer::fillJacobians() - - void - CommonInternalsMetricBundleOptimizer::updateParametersC(Vector const& deltaC) - { - switch (_mode) - { - case FULL_BUNDLE_FOCAL_AND_RADIAL_K1: - { - _K[0][0] += deltaC[0]; - _K[1][1] = _cachedAspectRatio * _K[0][0]; - _distortion.k1 += deltaC[1]; - break; - } - case FULL_BUNDLE_FOCAL_AND_RADIAL: - { - _K[0][0] += deltaC[0]; - _K[1][1] = _cachedAspectRatio * _K[0][0]; - _distortion.k1 += deltaC[1]; - _distortion.k2 += deltaC[2]; - break; - } - case FULL_BUNDLE_RADIAL_TANGENTIAL: - { - _distortion.p1 += deltaC[5]; - _distortion.p2 += deltaC[6]; - // No break here! - } - case FULL_BUNDLE_RADIAL: - { - _distortion.k1 += deltaC[3]; - _distortion.k2 += deltaC[4]; - // No break here! - } - case FULL_BUNDLE_FOCAL_LENGTH_PP: - { - _K[0][2] += deltaC[1]; - _K[1][2] += deltaC[2]; - // No break here! - } - case FULL_BUNDLE_FOCAL_LENGTH: - { - _K[0][0] += deltaC[0]; - _K[1][1] = _cachedAspectRatio * _K[0][0]; - } - case FULL_BUNDLE_METRIC: - { - } - } // end switch - } // end CommonInternalsMetricBundleOptimizer::updateParametersC() - - //---------------------------------------------------------------------- - - void - VaryingInternalsMetricBundleOptimizer::fillJacobians(Matrix& Ak, - Matrix& Bk, - Matrix& Ck, - int i, int j, int k) - { - Vector3d XX; - Matrix3x6d dXX_dRT; - Matrix3x3d dXX_dX; - this->poseDerivatives(i, j, XX, dXX_dRT, dXX_dX); - - Vector2d xu; // undistorted image point - xu[0] = XX[0] / XX[2]; - xu[1] = XX[1] / XX[2]; - - Vector2d const xd = _distortions[i](xu); // distorted image point - - double const focalLength = _cams[i].getFocalLength(); - double const aspectRatio = _cams[i].getAspectRatio(); - - Matrix2x2d dp_dxd; - dp_dxd[0][0] = focalLength; dp_dxd[0][1] = 0; - dp_dxd[1][0] = 0; dp_dxd[1][1] = aspectRatio * focalLength; - - { - // First, lets do the derivative wrt the structure and motion parameters. - Matrix2x3d dxu_dXX; - dxu_dXX[0][0] = 1.0f / XX[2]; dxu_dXX[0][1] = 0; dxu_dXX[0][2] = -XX[0]/(XX[2]*XX[2]); - dxu_dXX[1][0] = 0; dxu_dXX[1][1] = 1.0f / XX[2]; dxu_dXX[1][2] = -XX[1]/(XX[2]*XX[2]); - - Matrix2x2d dxd_dxu = _distortions[i].derivativeWrtUndistortedPoint(xu); - - Matrix2x2d dp_dxu = dp_dxd * dxd_dxu; - Matrix2x3d dp_dXX = dp_dxu * dxu_dXX; - - Matrix2x6d dp_dRT; - - multiply_A_B(dp_dXX, dXX_dRT, dp_dRT); - copyMatrixSlice(dp_dRT, 0, 0, 2, 6, Ak, 0, 0); - multiply_A_B(dp_dXX, dXX_dX, Bk); - } // end scope - - switch (_mode) - { - case FULL_BUNDLE_RADIAL_TANGENTIAL: - { - Matrix2x2d dxd_dp1p2 = _distortions[i].derivativeWrtTangentialParameters(xu); - Matrix2x2d d_dp1p2 = dp_dxd * dxd_dp1p2; - copyMatrixSlice(d_dp1p2, 0, 0, 2, 2, Ak, 0, 11); - // No break here! - } - case FULL_BUNDLE_RADIAL: - { - Matrix2x2d dxd_dk1k2 = _distortions[i].derivativeWrtRadialParameters(xu); - Matrix2x2d d_dk1k2 = dp_dxd * dxd_dk1k2; - copyMatrixSlice(d_dk1k2, 0, 0, 2, 2, Ak, 0, 9); - // No break here! - } - case FULL_BUNDLE_FOCAL_LENGTH_PP: - { - Ak[0][7] = 1; Ak[0][8] = 0; - Ak[1][7] = 0; Ak[1][8] = 1; - // No break here! - } - case FULL_BUNDLE_FOCAL_LENGTH: - { - Ak[0][6] = xd[0]; - Ak[1][6] = xd[1]; - } - case FULL_BUNDLE_METRIC: - { - } - } // end switch - } // end VaryingInternalsMetricBundleOptimizer::fillJacobians() - - void - VaryingInternalsMetricBundleOptimizer::updateParametersA(VectorArray const& deltaAi) - { - Vector3d T, omega; - Matrix3x3d R0, dR, K; - - for (int i = _nNonvaryingA; i < _nParametersA; ++i) - { - Vector const& deltaA = deltaAi[i]; - - T = _cams[i].getTranslation(); - T[0] += deltaA[0]; - T[1] += deltaA[1]; - T[2] += deltaA[2]; - _cams[i].setTranslation(T); - - // Create incremental rotation using Rodriguez formula. - R0 = _cams[i].getRotation(); - omega[0] = deltaA[3]; - omega[1] = deltaA[4]; - omega[2] = deltaA[5]; - createRotationMatrixRodriguez(omega, dR); - _cams[i].setRotation(dR * R0); - - K = _cams[i].getIntrinsic(); - - switch (_mode) - { - case FULL_BUNDLE_RADIAL_TANGENTIAL: - { - _distortions[i].p1 += deltaA[11]; - _distortions[i].p2 += deltaA[12]; - // No break here! - } - case FULL_BUNDLE_RADIAL: - { - _distortions[i].k1 += deltaA[9]; - _distortions[i].k2 += deltaA[10]; - // No break here! - } - case FULL_BUNDLE_FOCAL_LENGTH_PP: - { - K[0][2] += deltaA[7]; - K[1][2] += deltaA[8]; - // No break here! - } - case FULL_BUNDLE_FOCAL_LENGTH: - { - double const ar = K[1][1] / K[0][0]; - K[0][0] += deltaA[6]; - K[1][1] = ar * K[0][0]; - } - case FULL_BUNDLE_METRIC: - { - } - } // end switch - _cams[i].setIntrinsic(K); - } // end for (i) - } // end VaryingInternalsMetricBundleOptimizer::updateParametersC() - -} // end namespace V3D - -#endif // defined(V3DLIB_ENABLE_SUITESPARSE) diff --git a/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h b/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h deleted file mode 100644 index 339e174ed9e..00000000000 --- a/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h +++ /dev/null @@ -1,352 +0,0 @@ -// -*- C++ -*- -/* -Copyright (c) 2008 University of North Carolina at Chapel Hill - -This file is part of SSBA (Simple Sparse Bundle Adjustment). - -SSBA is free software: you can redistribute it and/or modify it under the -terms of the GNU Lesser General Public License as published by the Free -Software Foundation, either version 3 of the License, or (at your option) any -later version. - -SSBA is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. - -You should have received a copy of the GNU Lesser General Public License along -with SSBA. If not, see . -*/ - -#ifndef V3D_METRICBUNDLE_H -#define V3D_METRICBUNDLE_H - -# if defined(V3DLIB_ENABLE_SUITESPARSE) - -#include "Math/v3d_optimization.h" -#include "Math/v3d_linear.h" -#include "Math/v3d_linear_utils.h" -#include "Geometry/v3d_cameramatrix.h" -#include "Geometry/v3d_distortion.h" - -namespace V3D -{ - - // This structure provides some helper functions common to all metric BAs - struct MetricBundleOptimizerBase : public SparseLevenbergOptimizer - { - typedef SparseLevenbergOptimizer Base; - - MetricBundleOptimizerBase(double inlierThreshold, - vector& cams, - vector& Xs, - vector const& measurements, - vector const& corrspondingView, - vector const& corrspondingPoint, - int nAddParamsA, int nParamsC) - : SparseLevenbergOptimizer(2, cams.size(), 6+nAddParamsA, Xs.size(), 3, nParamsC, - corrspondingView, corrspondingPoint), - _cams(cams), _Xs(Xs), _measurements(measurements), - _savedTranslations(cams.size()), _savedRotations(cams.size()), - _savedXs(Xs.size()), - _inlierThreshold(inlierThreshold), _cachedParamLength(0.0) - { - // Since we assume that BA does not alter the inputs too much, - // we compute the overall length of the parameter vector in advance - // and return that value as the result of getParameterLength(). - for (int i = _nNonvaryingA; i < _nParametersA; ++i) - { - _cachedParamLength += sqrNorm_L2(_cams[i].getTranslation()); - _cachedParamLength += 3.0; // Assume eye(3) for R. - } - for (int j = _nNonvaryingB; j < _nParametersB; ++j) - _cachedParamLength += sqrNorm_L2(_Xs[j]); - - _cachedParamLength = sqrt(_cachedParamLength); - } - - // Huber robust cost function. - virtual void fillWeights(VectorArray const& residual, Vector& w) - { - for (unsigned int k = 0; k < w.size(); ++k) - { - Vector const& r = residual[k]; - double const e = norm_L2(r); - w[k] = (e < _inlierThreshold) ? 1.0 : sqrt(_inlierThreshold / e); - } // end for (k) - } - - virtual double getParameterLength() const - { - return _cachedParamLength; - } - - virtual void updateParametersA(VectorArray const& deltaAi); - virtual void updateParametersB(VectorArray const& deltaBj); - virtual void updateParametersC(Vector const& deltaC) - { - (void)deltaC; - } - - virtual void saveAllParameters() - { - for (int i = _nNonvaryingA; i < _nParametersA; ++i) - { - _savedTranslations[i] = _cams[i].getTranslation(); - _savedRotations[i] = _cams[i].getRotation(); - } - _savedXs = _Xs; - } - - virtual void restoreAllParameters() - { - for (int i = _nNonvaryingA; i < _nParametersA; ++i) - { - _cams[i].setTranslation(_savedTranslations[i]); - _cams[i].setRotation(_savedRotations[i]); - } - _Xs = _savedXs; - } - - protected: - typedef InlineMatrix Matrix3x6d; - - void poseDerivatives(int i, int j, Vector3d& XX, - Matrix3x6d& d_dRT, Matrix3x3d& d_dX) const; - - vector& _cams; - vector& _Xs; - - vector const& _measurements; - - vector _savedTranslations; - vector _savedRotations; - vector _savedXs; - - double const _inlierThreshold; - double _cachedParamLength; - }; // end struct MetricBundleOptimizerBase - - struct StdMetricBundleOptimizer : public MetricBundleOptimizerBase - { - typedef MetricBundleOptimizerBase Base; - - StdMetricBundleOptimizer(double inlierThreshold, - vector& cams, - vector& Xs, - vector const& measurements, - vector const& corrspondingView, - vector const& corrspondingPoint) - : MetricBundleOptimizerBase(inlierThreshold, cams, Xs, measurements, - corrspondingView, corrspondingPoint, 0, 0) - { } - - virtual void evalResidual(VectorArray& e) - { - for (unsigned int k = 0; k < e.count(); ++k) - { - int const i = _correspondingParamA[k]; - int const j = _correspondingParamB[k]; - - Vector2d const q = _cams[i].projectPoint(_Xs[j]); - e[k][0] = q[0] - _measurements[k][0]; - e[k][1] = q[1] - _measurements[k][1]; - } - } - - virtual void fillJacobians(Matrix& Ak, Matrix& Bk, Matrix& Ck, - int i, int j, int k); - }; // end struct StdMetricBundleOptimizer - -//---------------------------------------------------------------------- - - enum - { - FULL_BUNDLE_METRIC = 0, - FULL_BUNDLE_FOCAL_LENGTH = 1, // f - FULL_BUNDLE_FOCAL_LENGTH_PP = 2, // f, cx, cy - FULL_BUNDLE_RADIAL = 3, // f, cx, cy, k1, k2 - FULL_BUNDLE_RADIAL_TANGENTIAL = 4, // f, cx, cy, k1, k2, p1, p2 - FULL_BUNDLE_FOCAL_AND_RADIAL_K1 = 5, // f, k1 - FULL_BUNDLE_FOCAL_AND_RADIAL = 6, // f, k1, k2 - }; - - struct CommonInternalsMetricBundleOptimizer : public MetricBundleOptimizerBase - { - static int globalParamDimensionFromMode(int mode) - { - switch (mode) - { - case FULL_BUNDLE_METRIC: return 0; - case FULL_BUNDLE_FOCAL_LENGTH: return 1; - case FULL_BUNDLE_FOCAL_LENGTH_PP: return 3; - case FULL_BUNDLE_RADIAL: return 5; - case FULL_BUNDLE_RADIAL_TANGENTIAL: return 7; - case FULL_BUNDLE_FOCAL_AND_RADIAL_K1: return 2; - case FULL_BUNDLE_FOCAL_AND_RADIAL: return 3; - } - return 0; - } - - typedef MetricBundleOptimizerBase Base; - - CommonInternalsMetricBundleOptimizer(int mode, - double inlierThreshold, - Matrix3x3d& K, - StdDistortionFunction& distortion, - vector& cams, - vector& Xs, - vector const& measurements, - vector const& corrspondingView, - vector const& corrspondingPoint) - : MetricBundleOptimizerBase(inlierThreshold, cams, Xs, measurements, - corrspondingView, corrspondingPoint, - 0, globalParamDimensionFromMode(mode)), - _mode(mode), _K(K), _distortion(distortion) - { - _cachedAspectRatio = K[1][1] / K[0][0]; - } - - Vector2d projectPoint(Vector3d const& X, int i) const - { - Vector3d const XX = _cams[i].transformPointIntoCameraSpace(X); - Vector2d p; - p[0] = XX[0] / XX[2]; - p[1] = XX[1] / XX[2]; - p = _distortion(p); - Vector2d res; - res[0] = _K[0][0] * p[0] + _K[0][1] * p[1] + _K[0][2]; - res[1] = _K[1][1] * p[1] + _K[1][2]; - return res; - } - - virtual void evalResidual(VectorArray& e) - { - for (unsigned int k = 0; k < e.count(); ++k) - { - int const i = _correspondingParamA[k]; - int const j = _correspondingParamB[k]; - - Vector2d const q = this->projectPoint(_Xs[j], i); - e[k][0] = q[0] - _measurements[k][0]; - e[k][1] = q[1] - _measurements[k][1]; - } - } - - virtual void fillJacobians(Matrix& Ak, Matrix& Bk, Matrix& Ck, - int i, int j, int k); - - virtual void updateParametersC(Vector const& deltaC); - - virtual void saveAllParameters() - { - Base::saveAllParameters(); - _savedK = _K; - _savedDistortion = _distortion; - } - - virtual void restoreAllParameters() - { - Base::restoreAllParameters(); - _K = _savedK; - _distortion = _savedDistortion; - } - - protected: - int _mode; - Matrix3x3d& _K; - StdDistortionFunction& _distortion; - - Matrix3x3d _savedK; - StdDistortionFunction _savedDistortion; - double _cachedAspectRatio; - }; // end struct CommonInternalsMetricBundleOptimizer - -//---------------------------------------------------------------------- - - struct VaryingInternalsMetricBundleOptimizer : public MetricBundleOptimizerBase - { - static int extParamDimensionFromMode(int mode) - { - switch (mode) - { - case FULL_BUNDLE_METRIC: return 0; - case FULL_BUNDLE_FOCAL_LENGTH: return 1; - case FULL_BUNDLE_FOCAL_LENGTH_PP: return 3; - case FULL_BUNDLE_RADIAL: return 5; - case FULL_BUNDLE_RADIAL_TANGENTIAL: return 7; - case FULL_BUNDLE_FOCAL_AND_RADIAL_K1: return 2; - case FULL_BUNDLE_FOCAL_AND_RADIAL: return 3; - } - return 0; - } - - typedef MetricBundleOptimizerBase Base; - - VaryingInternalsMetricBundleOptimizer(int mode, - double inlierThreshold, - std::vector& distortions, - vector& cams, - vector& Xs, - vector const& measurements, - vector const& corrspondingView, - vector const& corrspondingPoint) - : MetricBundleOptimizerBase(inlierThreshold, cams, Xs, measurements, - corrspondingView, corrspondingPoint, - extParamDimensionFromMode(mode), 0), - _mode(mode), _distortions(distortions), - _savedKs(cams.size()), _savedDistortions(cams.size()) - { } - - Vector2d projectPoint(Vector3d const& X, int i) const - { - return _cams[i].projectPoint(_distortions[i], X); - } - - virtual void evalResidual(VectorArray& e) - { - for (unsigned int k = 0; k < e.count(); ++k) - { - int const i = _correspondingParamA[k]; - int const j = _correspondingParamB[k]; - - Vector2d const q = this->projectPoint(_Xs[j], i); - e[k][0] = q[0] - _measurements[k][0]; - e[k][1] = q[1] - _measurements[k][1]; - } - } - - virtual void fillJacobians(Matrix& Ak, Matrix& Bk, Matrix& Ck, - int i, int j, int k); - - virtual void updateParametersA(VectorArray const& deltaAi); - - virtual void saveAllParameters() - { - Base::saveAllParameters(); - for (int i = _nNonvaryingA; i < _nParametersA; ++i) - _savedKs[i] = _cams[i].getIntrinsic(); - std::copy(_distortions.begin(), _distortions.end(), _savedDistortions.begin()); - } - - virtual void restoreAllParameters() - { - Base::restoreAllParameters(); - for (int i = _nNonvaryingA; i < _nParametersA; ++i) - _cams[i].setIntrinsic(_savedKs[i]); - std::copy(_savedDistortions.begin(), _savedDistortions.end(), _distortions.begin()); - } - - protected: - int _mode; - std::vector& _distortions; - - std::vector _savedKs; - std::vector _savedDistortions; - }; // end struct VaryingInternalsMetricBundleOptimizer - -} // end namespace V3D - -# endif - -#endif diff --git a/extern/libmv/third_party/ssba/Math/v3d_linear.h b/extern/libmv/third_party/ssba/Math/v3d_linear.h deleted file mode 100644 index 7d6e898169c..00000000000 --- a/extern/libmv/third_party/ssba/Math/v3d_linear.h +++ /dev/null @@ -1,923 +0,0 @@ -// -*- C++ -*- -/* -Copyright (c) 2008 University of North Carolina at Chapel Hill - -This file is part of SSBA (Simple Sparse Bundle Adjustment). - -SSBA is free software: you can redistribute it and/or modify it under the -terms of the GNU Lesser General Public License as published by the Free -Software Foundation, either version 3 of the License, or (at your option) any -later version. - -SSBA is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. - -You should have received a copy of the GNU Lesser General Public License along -with SSBA. If not, see . -*/ - -#ifndef V3D_LINEAR_H -#define V3D_LINEAR_H - -#include -#include -#include -#include - -namespace V3D -{ - using namespace std; - - //! Unboxed vector type - template - struct InlineVectorBase - { - typedef Elem value_type; - typedef Elem element_type; - - typedef Elem const * const_iterator; - typedef Elem * iterator; - - static unsigned int size() { return Size; } - - Elem& operator[](unsigned int i) { return _vec[i]; } - Elem operator[](unsigned int i) const { return _vec[i]; } - - Elem& operator()(unsigned int i) { return _vec[i-1]; } - Elem operator()(unsigned int i) const { return _vec[i-1]; } - - const_iterator begin() const { return _vec; } - iterator begin() { return _vec; } - const_iterator end() const { return _vec + Size; } - iterator end() { return _vec + Size; } - - void newsize(unsigned int sz) const - { - assert(sz == Size); - } - - protected: - Elem _vec[Size]; - }; - - //! Boxed (heap allocated) vector. - template - struct VectorBase - { - typedef Elem value_type; - typedef Elem element_type; - - typedef Elem const * const_iterator; - typedef Elem * iterator; - - VectorBase() - : _size(0), _ownsVec(true), _vec(0) - { } - - VectorBase(unsigned int size) - : _size(size), _ownsVec(true), _vec(0) - { - if (size > 0) _vec = new Elem[size]; - } - - VectorBase(unsigned int size, Elem * values) - : _size(size), _ownsVec(false), _vec(values) - { } - - VectorBase(VectorBase const& a) - : _size(0), _ownsVec(true), _vec(0) - { - _size = a._size; - if (_size == 0) return; - _vec = new Elem[_size]; - std::copy(a._vec, a._vec + _size, _vec); - } - - ~VectorBase() { if (_ownsVec && _vec != 0) delete [] _vec; } - - VectorBase& operator=(VectorBase const& a) - { - if (this == &a) return *this; - - this->newsize(a._size); - std::copy(a._vec, a._vec + _size, _vec); - return *this; - } - - unsigned int size() const { return _size; } - - VectorBase& newsize(unsigned int sz) - { - if (sz == _size) return *this; - assert(_ownsVec); - - __destroy(); - _size = sz; - if (_size > 0) _vec = new Elem[_size]; - - return *this; - } - - - Elem& operator[](unsigned int i) { return _vec[i]; } - Elem operator[](unsigned int i) const { return _vec[i]; } - - Elem& operator()(unsigned int i) { return _vec[i-1]; } - Elem operator()(unsigned int i) const { return _vec[i-1]; } - - const_iterator begin() const { return _vec; } - iterator begin() { return _vec; } - const_iterator end() const { return _vec + _size; } - iterator end() { return _vec + _size; } - - protected: - void __destroy() - { - assert(_ownsVec); - - if (_vec != 0) delete [] _vec; - _size = 0; - _vec = 0; - } - - unsigned int _size; - bool _ownsVec; - Elem * _vec; - }; - - template - struct InlineMatrixBase - { - typedef Elem value_type; - typedef Elem element_type; - - typedef Elem * iterator; - typedef Elem const * const_iterator; - - static unsigned int num_rows() { return Rows; } - static unsigned int num_cols() { return Cols; } - - Elem * operator[](unsigned int row) { return _m[row]; } - Elem const * operator[](unsigned int row) const { return _m[row]; } - - Elem& operator()(unsigned int row, unsigned int col) { return _m[row-1][col-1]; } - Elem operator()(unsigned int row, unsigned int col) const { return _m[row-1][col-1]; } - - template - void getRowSlice(unsigned int row, unsigned int first, unsigned int last, Vec& dst) const - { - for (unsigned int c = first; c < last; ++c) dst[c-first] = _m[row][c]; - } - - template - void getColumnSlice(unsigned int first, unsigned int len, unsigned int col, Vec& dst) const - { - for (unsigned int r = 0; r < len; ++r) dst[r] = _m[r+first][col]; - } - - void newsize(unsigned int rows, unsigned int cols) const - { - assert(rows == Rows && cols == Cols); - } - - const_iterator begin() const { return &_m[0][0]; } - iterator begin() { return &_m[0][0]; } - const_iterator end() const { return &_m[0][0] + Rows*Cols; } - iterator end() { return &_m[0][0] + Rows*Cols; } - - protected: - Elem _m[Rows][Cols]; - }; - - template - struct MatrixBase - { - typedef Elem value_type; - typedef Elem element_type; - - typedef Elem const * const_iterator; - typedef Elem * iterator; - - MatrixBase() - : _rows(0), _cols(0), _ownsData(true), _m(0) - { } - - MatrixBase(unsigned int rows, unsigned int cols) - : _rows(rows), _cols(cols), _ownsData(true), _m(0) - { - if (_rows * _cols == 0) return; - _m = new Elem[rows*cols]; - } - - MatrixBase(unsigned int rows, unsigned int cols, Elem * values) - : _rows(rows), _cols(cols), _ownsData(false), _m(values) - { } - - MatrixBase(MatrixBase const& a) - : _ownsData(true), _m(0) - { - _rows = a._rows; _cols = a._cols; - if (_rows * _cols == 0) return; - _m = new Elem[_rows*_cols]; - std::copy(a._m, a._m+_rows*_cols, _m); - } - - ~MatrixBase() - { - if (_ownsData && _m != 0) delete [] _m; - } - - MatrixBase& operator=(MatrixBase const& a) - { - if (this == &a) return *this; - - this->newsize(a.num_rows(), a.num_cols()); - - std::copy(a._m, a._m+_rows*_cols, _m); - return *this; - } - - void newsize(unsigned int rows, unsigned int cols) - { - if (rows == _rows && cols == _cols) return; - - assert(_ownsData); - - __destroy(); - - _rows = rows; - _cols = cols; - if (_rows * _cols == 0) return; - _m = new Elem[rows*cols]; - } - - unsigned int num_rows() const { return _rows; } - unsigned int num_cols() const { return _cols; } - - Elem * operator[](unsigned int row) { return _m + row*_cols; } - Elem const * operator[](unsigned int row) const { return _m + row*_cols; } - - Elem& operator()(unsigned int row, unsigned int col) { return _m[(row-1)*_cols + col-1]; } - Elem operator()(unsigned int row, unsigned int col) const { return _m[(row-1)*_cols + col-1]; } - - const_iterator begin() const { return _m; } - iterator begin() { return _m; } - const_iterator end() const { return _m + _rows*_cols; } - iterator end() { return _m + _rows*_cols; } - - template - void getRowSlice(unsigned int row, unsigned int first, unsigned int last, Vec& dst) const - { - Elem const * v = (*this)[row]; - for (unsigned int c = first; c < last; ++c) dst[c-first] = v[c]; - } - - template - void getColumnSlice(unsigned int first, unsigned int len, unsigned int col, Vec& dst) const - { - for (unsigned int r = 0; r < len; ++r) dst[r] = _m[r+first][col]; - } - - protected: - void __destroy() - { - assert(_ownsData); - if (_m != 0) delete [] _m; - _m = 0; - _rows = _cols = 0; - } - - unsigned int _rows, _cols; - bool _ownsData; - Elem * _m; - }; - - template - struct CCS_Matrix - { - CCS_Matrix() - : _rows(0), _cols(0) - { } - - CCS_Matrix(int const rows, int const cols, vector > const& nonZeros) - : _rows(rows), _cols(cols) - { - this->initialize(nonZeros); - } - - CCS_Matrix(CCS_Matrix const& b) - : _rows(b._rows), _cols(b._cols), - _colStarts(b._colStarts), _rowIdxs(b._rowIdxs), _destIdxs(b._destIdxs), _values(b._values) - { } - - CCS_Matrix& operator=(CCS_Matrix const& b) - { - if (this == &b) return *this; - _rows = b._rows; - _cols = b._cols; - _colStarts = b._colStarts; - _rowIdxs = b._rowIdxs; - _destIdxs = b._destIdxs; - _values = b._values; - return *this; - } - - void create(int const rows, int const cols, vector > const& nonZeros) - { - _rows = rows; - _cols = cols; - this->initialize(nonZeros); - } - - unsigned int num_rows() const { return _rows; } - unsigned int num_cols() const { return _cols; } - - int getNonzeroCount() const { return _values.size(); } - - T const * getValues() const { return &_values[0]; } - T * getValues() { return &_values[0]; } - - int const * getDestIndices() const { return &_destIdxs[0]; } - int const * getColumnStarts() const { return &_colStarts[0]; } - int const * getRowIndices() const { return &_rowIdxs[0]; } - - void getRowRange(unsigned int col, unsigned int& firstRow, unsigned int& lastRow) const - { - firstRow = _rowIdxs[_colStarts[col]]; - lastRow = _rowIdxs[_colStarts[col+1]-1]+1; - } - - template - void getColumnSlice(unsigned int first, unsigned int len, unsigned int col, Vec& dst) const - { - unsigned int const last = first + len; - - for (int r = 0; r < len; ++r) dst[r] = 0; // Fill vector with zeros - - int const colStart = _colStarts[col]; - int const colEnd = _colStarts[col+1]; - - int i = colStart; - int r; - // Skip rows less than the given start row - while (i < colEnd && (r = _rowIdxs[i]) < first) ++i; - - // Copy elements until the final row - while (i < colEnd && (r = _rowIdxs[i]) < last) - { - dst[r-first] = _values[i]; - ++i; - } - } // end getColumnSlice() - - int getColumnNonzeroCount(unsigned int col) const - { - int const colStart = _colStarts[col]; - int const colEnd = _colStarts[col+1]; - return colEnd - colStart; - } - - template - void getSparseColumn(unsigned int col, VecA& rows, VecB& values) const - { - int const colStart = _colStarts[col]; - int const colEnd = _colStarts[col+1]; - int const nnz = colEnd - colStart; - - for (int i = 0; i < nnz; ++i) - { - rows[i] = _rowIdxs[colStart + i]; - values[i] = _values[colStart + i]; - } - } - - protected: - struct NonzeroInfo - { - int row, col, serial; - - // Sort wrt the column first - bool operator<(NonzeroInfo const& rhs) const - { - if (col < rhs.col) return true; - if (col > rhs.col) return false; - return row < rhs.row; - } - }; - - void initialize(std::vector > const& nonZeros) - { - using namespace std; - - int const nnz = nonZeros.size(); - - _colStarts.resize(_cols + 1); - _rowIdxs.resize(nnz); - - vector nz(nnz); - for (int k = 0; k < nnz; ++k) - { - nz[k].row = nonZeros[k].first; - nz[k].col = nonZeros[k].second; - nz[k].serial = k; - } - - // Sort in column major order - std::sort(nz.begin(), nz.end()); - - for (size_t k = 0; k < nnz; ++k) _rowIdxs[k] = nz[k].row; - - int curCol = -1; - for (int k = 0; k < nnz; ++k) - { - NonzeroInfo const& el = nz[k]; - if (el.col != curCol) - { - // Update empty cols between - for (int c = curCol+1; c < el.col; ++c) _colStarts[c] = k; - - curCol = el.col; - _colStarts[curCol] = k; - } // end if - } // end for (k) - - // Update remaining columns - for (int c = curCol+1; c <= _cols; ++c) _colStarts[c] = nnz; - - _destIdxs.resize(nnz); - for (int k = 0; k < nnz; ++k) _destIdxs[nz[k].serial] = k; - - _values.resize(nnz); - } // end initialize() - - int _rows, _cols; - std::vector _colStarts; - std::vector _rowIdxs; - std::vector _destIdxs; - std::vector _values; - }; // end struct CCS_Matrix - -//---------------------------------------------------------------------- - - template - inline void - fillVector(Vec& v, Elem val) - { - // We do not use std::fill since we rely only on size() and operator[] member functions. - for (unsigned int i = 0; i < v.size(); ++i) v[i] = val; - } - - template - inline void - makeZeroVector(Vec& v) - { - fillVector(v, 0); - } - - template - inline void - copyVector(VecA const& src, VecB& dst) - { - assert(src.size() == dst.size()); - // We do not use std::fill since we rely only on size() and operator[] member functions. - for (unsigned int i = 0; i < src.size(); ++i) dst[i] = src[i]; - } - - template - inline void - copyVectorSlice(VecA const& src, unsigned int srcStart, unsigned int srcLen, - VecB& dst, unsigned int dstStart) - { - unsigned int const end = std::min(srcStart + srcLen, src.size()); - unsigned int const sz = dst.size(); - unsigned int i0, i1; - for (i0 = srcStart, i1 = dstStart; i0 < end && i1 < sz; ++i0, ++i1) dst[i1] = src[i0]; - } - - template - inline typename Vec::value_type - norm_L1(Vec const& v) - { - typename Vec::value_type res(0); - for (unsigned int i = 0; i < v.size(); ++i) res += fabs(v[i]); - return res; - } - - template - inline typename Vec::value_type - norm_Linf(Vec const& v) - { - typename Vec::value_type res(0); - for (unsigned int i = 0; i < v.size(); ++i) res = std::max(res, fabs(v[i])); - return res; - } - - template - inline typename Vec::value_type - norm_L2(Vec const& v) - { - typename Vec::value_type res(0); - for (unsigned int i = 0; i < v.size(); ++i) res += v[i]*v[i]; - return sqrt((double)res); - } - - template - inline typename Vec::value_type - sqrNorm_L2(Vec const& v) - { - typename Vec::value_type res(0); - for (unsigned int i = 0; i < v.size(); ++i) res += v[i]*v[i]; - return res; - } - - template - inline void - normalizeVector(Vec& v) - { - typename Vec::value_type norm(norm_L2(v)); - for (unsigned int i = 0; i < v.size(); ++i) v[i] /= norm; - } - - template - inline typename VecA::value_type - innerProduct(VecA const& a, VecB const& b) - { - assert(a.size() == b.size()); - typename VecA::value_type res(0); - for (unsigned int i = 0; i < a.size(); ++i) res += a[i] * b[i]; - return res; - } - - template - inline void - scaleVector(Elem s, VecA const& v, VecB& dst) - { - for (unsigned int i = 0; i < v.size(); ++i) dst[i] = s * v[i]; - } - - template - inline void - scaleVectorIP(Elem s, Vec& v) - { - typedef typename Vec::value_type Elem2; - for (unsigned int i = 0; i < v.size(); ++i) - v[i] = (Elem2)(v[i] * s); - } - - template - inline void - makeCrossProductVector(VecA const& v, VecB const& w, VecC& dst) - { - assert(v.size() == 3); - assert(w.size() == 3); - assert(dst.size() == 3); - dst[0] = v[1]*w[2] - v[2]*w[1]; - dst[1] = v[2]*w[0] - v[0]*w[2]; - dst[2] = v[0]*w[1] - v[1]*w[0]; - } - - template - inline void - addVectors(VecA const& v, VecB const& w, VecC& dst) - { - assert(v.size() == w.size()); - assert(v.size() == dst.size()); - for (unsigned int i = 0; i < v.size(); ++i) dst[i] = v[i] + w[i]; - } - - template - inline void - subtractVectors(VecA const& v, VecB const& w, VecC& dst) - { - assert(v.size() == w.size()); - assert(v.size() == dst.size()); - for (unsigned int i = 0; i < v.size(); ++i) dst[i] = v[i] - w[i]; - } - - template - inline void - copyMatrix(MatA const& src, MatB& dst) - { - unsigned int const rows = src.num_rows(); - unsigned int const cols = src.num_cols(); - assert(dst.num_rows() == rows); - assert(dst.num_cols() == cols); - for (unsigned int c = 0; c < cols; ++c) - for (unsigned int r = 0; r < rows; ++r) dst[r][c] = src[r][c]; - } - - template - inline void - copyMatrixSlice(MatA const& src, unsigned int rowStart, unsigned int colStart, unsigned int rowLen, unsigned int colLen, - MatB& dst, unsigned int dstRow, unsigned int dstCol) - { - unsigned int const rows = dst.num_rows(); - unsigned int const cols = dst.num_cols(); - - unsigned int const rowEnd = std::min(rowStart + rowLen, src.num_rows()); - unsigned int const colEnd = std::min(colStart + colLen, src.num_cols()); - - unsigned int c0, c1, r0, r1; - - for (c0 = colStart, c1 = dstCol; c0 < colEnd && c1 < cols; ++c0, ++c1) - for (r0 = rowStart, r1 = dstRow; r0 < rowEnd && r1 < rows; ++r0, ++r1) - dst[r1][c1] = src[r0][c0]; - } - - template - inline void - makeTransposedMatrix(MatA const& src, MatB& dst) - { - unsigned int const rows = src.num_rows(); - unsigned int const cols = src.num_cols(); - assert(dst.num_cols() == rows); - assert(dst.num_rows() == cols); - for (unsigned int c = 0; c < cols; ++c) - for (unsigned int r = 0; r < rows; ++r) dst[c][r] = src[r][c]; - } - - template - inline void - fillMatrix(Mat& m, typename Mat::value_type val) - { - unsigned int const rows = m.num_rows(); - unsigned int const cols = m.num_cols(); - for (unsigned int c = 0; c < cols; ++c) - for (unsigned int r = 0; r < rows; ++r) m[r][c] = val; - } - - template - inline void - makeZeroMatrix(Mat& m) - { - fillMatrix(m, 0); - } - - template - inline void - makeIdentityMatrix(Mat& m) - { - makeZeroMatrix(m); - unsigned int const rows = m.num_rows(); - unsigned int const cols = m.num_cols(); - unsigned int n = std::min(rows, cols); - for (unsigned int i = 0; i < n; ++i) - m[i][i] = 1; - } - - template - inline void - makeCrossProductMatrix(Vec const& v, Mat& m) - { - assert(v.size() == 3); - assert(m.num_rows() == 3); - assert(m.num_cols() == 3); - m[0][0] = 0; m[0][1] = -v[2]; m[0][2] = v[1]; - m[1][0] = v[2]; m[1][1] = 0; m[1][2] = -v[0]; - m[2][0] = -v[1]; m[2][1] = v[0]; m[2][2] = 0; - } - - template - inline void - makeOuterProductMatrix(Vec const& v, Mat& m) - { - assert(m.num_cols() == m.num_rows()); - assert(v.size() == m.num_cols()); - unsigned const sz = v.size(); - for (unsigned r = 0; r < sz; ++r) - for (unsigned c = 0; c < sz; ++c) m[r][c] = v[r]*v[c]; - } - - template - inline void - makeOuterProductMatrix(VecA const& u, VecB const& v, Mat& m) - { - assert(m.num_cols() == m.num_rows()); - assert(u.size() == m.num_cols()); - assert(v.size() == m.num_cols()); - unsigned const sz = u.size(); - for (unsigned r = 0; r < sz; ++r) - for (unsigned c = 0; c < sz; ++c) m[r][c] = u[r]*v[c]; - } - - template - void addMatrices(MatA const& a, MatB const& b, MatC& dst) - { - assert(a.num_cols() == b.num_cols()); - assert(a.num_rows() == b.num_rows()); - assert(dst.num_cols() == a.num_cols()); - assert(dst.num_rows() == a.num_rows()); - - unsigned int const rows = a.num_rows(); - unsigned int const cols = a.num_cols(); - - for (unsigned r = 0; r < rows; ++r) - for (unsigned c = 0; c < cols; ++c) dst[r][c] = a[r][c] + b[r][c]; - } - - template - void addMatricesIP(MatA const& a, MatB& dst) - { - assert(dst.num_cols() == a.num_cols()); - assert(dst.num_rows() == a.num_rows()); - - unsigned int const rows = a.num_rows(); - unsigned int const cols = a.num_cols(); - - for (unsigned r = 0; r < rows; ++r) - for (unsigned c = 0; c < cols; ++c) dst[r][c] += a[r][c]; - } - - template - void subtractMatrices(MatA const& a, MatB const& b, MatC& dst) - { - assert(a.num_cols() == b.num_cols()); - assert(a.num_rows() == b.num_rows()); - assert(dst.num_cols() == a.num_cols()); - assert(dst.num_rows() == a.num_rows()); - - unsigned int const rows = a.num_rows(); - unsigned int const cols = a.num_cols(); - - for (unsigned r = 0; r < rows; ++r) - for (unsigned c = 0; c < cols; ++c) dst[r][c] = a[r][c] - b[r][c]; - } - - template - inline void - makeScaledMatrix(MatA const& m, Elem scale, MatB& dst) - { - unsigned int const rows = m.num_rows(); - unsigned int const cols = m.num_cols(); - for (unsigned int c = 0; c < cols; ++c) - for (unsigned int r = 0; r < rows; ++r) dst[r][c] = m[r][c] * scale; - } - - template - inline void - scaleMatrixIP(Elem scale, Mat& m) - { - unsigned int const rows = m.num_rows(); - unsigned int const cols = m.num_cols(); - for (unsigned int c = 0; c < cols; ++c) - for (unsigned int r = 0; r < rows; ++r) m[r][c] *= scale; - } - - template - inline void - multiply_A_v(Mat const& m, VecA const& in, VecB& dst) - { - unsigned int const rows = m.num_rows(); - unsigned int const cols = m.num_cols(); - assert(in.size() == cols); - assert(dst.size() == rows); - - makeZeroVector(dst); - - for (unsigned int r = 0; r < rows; ++r) - for (unsigned int c = 0; c < cols; ++c) dst[r] += m[r][c] * in[c]; - } - - template - inline void - multiply_A_v_projective(Mat const& m, VecA const& in, VecB& dst) - { - unsigned int const rows = m.num_rows(); - unsigned int const cols = m.num_cols(); - assert(in.size() == cols-1); - assert(dst.size() == rows-1); - - typename VecB::value_type w = m(rows-1, cols-1); - unsigned int r, i; - for (i = 0; i < cols-1; ++i) w += m(rows-1, i) * in[i]; - for (r = 0; r < rows-1; ++r) dst[r] = m(r, cols-1); - for (r = 0; r < rows-1; ++r) - for (unsigned int c = 0; c < cols-1; ++c) dst[r] += m[r][c] * in[c]; - for (i = 0; i < rows-1; ++i) dst[i] /= w; - } - - template - inline void - multiply_A_v_affine(Mat const& m, VecA const& in, VecB& dst) - { - unsigned int const rows = m.num_rows(); - unsigned int const cols = m.num_cols(); - assert(in.size() == cols-1); - assert(dst.size() == rows); - - unsigned int r; - - for (r = 0; r < rows; ++r) dst[r] = m(r, cols-1); - for (r = 0; r < rows; ++r) - for (unsigned int c = 0; c < cols-1; ++c) dst[r] += m[r][c] * in[c]; - } - - template - inline void - multiply_At_v(Mat const& m, VecA const& in, VecB& dst) - { - unsigned int const rows = m.num_rows(); - unsigned int const cols = m.num_cols(); - assert(in.size() == rows); - assert(dst.size() == cols); - - makeZeroVector(dst); - for (unsigned int c = 0; c < cols; ++c) - for (unsigned int r = 0; r < rows; ++r) dst[c] += m[r][c] * in[r]; - } - - template - inline void - multiply_At_A(MatA const& a, MatB& dst) - { - assert(dst.num_rows() == a.num_cols()); - assert(dst.num_cols() == a.num_cols()); - - typedef typename MatB::value_type Elem; - - Elem accum; - for (unsigned int r = 0; r < a.num_cols(); ++r) - for (unsigned int c = 0; c < a.num_cols(); ++c) - { - accum = 0; - for (unsigned int k = 0; k < a.num_rows(); ++k) accum += a[k][r] * a[k][c]; - dst[r][c] = accum; - } - } - - template - inline void - multiply_A_B(MatA const& a, MatB const& b, MatC& dst) - { - assert(a.num_cols() == b.num_rows()); - assert(dst.num_rows() == a.num_rows()); - assert(dst.num_cols() == b.num_cols()); - - typedef typename MatC::value_type Elem; - - Elem accum; - for (unsigned int r = 0; r < a.num_rows(); ++r) - for (unsigned int c = 0; c < b.num_cols(); ++c) - { - accum = 0; - for (unsigned int k = 0; k < a.num_cols(); ++k) accum += a[r][k] * b[k][c]; - dst[r][c] = accum; - } - } - - template - inline void - multiply_At_B(MatA const& a, MatB const& b, MatC& dst) - { - assert(a.num_rows() == b.num_rows()); - assert(dst.num_rows() == a.num_cols()); - assert(dst.num_cols() == b.num_cols()); - - typedef typename MatC::value_type Elem; - - Elem accum; - for (unsigned int r = 0; r < a.num_cols(); ++r) - for (unsigned int c = 0; c < b.num_cols(); ++c) - { - accum = 0; - for (unsigned int k = 0; k < a.num_rows(); ++k) accum += a[k][r] * b[k][c]; - dst[r][c] = accum; - } - } - - template - inline void - multiply_A_Bt(MatA const& a, MatB const& b, MatC& dst) - { - assert(a.num_cols() == b.num_cols()); - assert(dst.num_rows() == a.num_rows()); - assert(dst.num_cols() == b.num_rows()); - - typedef typename MatC::value_type Elem; - - Elem accum; - for (unsigned int r = 0; r < a.num_rows(); ++r) - for (unsigned int c = 0; c < b.num_rows(); ++c) - { - accum = 0; - for (unsigned int k = 0; k < a.num_cols(); ++k) accum += a[r][k] * b[c][k]; - dst[r][c] = accum; - } - } - - template - inline void - transposeMatrixIP(Mat& a) - { - assert(a.num_rows() == a.num_cols()); - - for (unsigned int r = 0; r < a.num_rows(); ++r) - for (unsigned int c = 0; c < r; ++c) - std::swap(a[r][c], a[c][r]); - } - -} // end namespace V3D - -#endif diff --git a/extern/libmv/third_party/ssba/Math/v3d_linear_utils.h b/extern/libmv/third_party/ssba/Math/v3d_linear_utils.h deleted file mode 100644 index 969ec99694f..00000000000 --- a/extern/libmv/third_party/ssba/Math/v3d_linear_utils.h +++ /dev/null @@ -1,391 +0,0 @@ -// -*- C++ -*- -/* -Copyright (c) 2008 University of North Carolina at Chapel Hill - -This file is part of SSBA (Simple Sparse Bundle Adjustment). - -SSBA is free software: you can redistribute it and/or modify it under the -terms of the GNU Lesser General Public License as published by the Free -Software Foundation, either version 3 of the License, or (at your option) any -later version. - -SSBA is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. - -You should have received a copy of the GNU Lesser General Public License along -with SSBA. If not, see . -*/ - -#ifndef V3D_LINEAR_UTILS_H -#define V3D_LINEAR_UTILS_H - -#include "Math/v3d_linear.h" - -#include - -namespace V3D -{ - - template - struct InlineVector : public InlineVectorBase - { - }; // end struct InlineVector - - template - struct Vector : public VectorBase - { - Vector() - : VectorBase() - { } - - Vector(unsigned int size) - : VectorBase(size) - { } - - Vector(unsigned int size, Elem * values) - : VectorBase(size, values) - { } - - Vector(Vector const& a) - : VectorBase(a) - { } - - Vector& operator=(Vector const& a) - { - (VectorBase::operator=)(a); - return *this; - } - - Vector& operator+=(Vector const& rhs) - { - addVectorsIP(rhs, *this); - return *this; - } - - Vector& operator*=(Elem scale) - { - scaleVectorsIP(scale, *this); - return *this; - } - - Vector operator+(Vector const& rhs) const - { - Vector res(this->size()); - addVectors(*this, rhs, res); - return res; - } - - Vector operator-(Vector const& rhs) const - { - Vector res(this->size()); - subtractVectors(*this, rhs, res); - return res; - } - - Elem operator*(Vector const& rhs) const - { - return innerProduct(*this, rhs); - } - - }; // end struct Vector - - template - struct InlineMatrix : public InlineMatrixBase - { - }; // end struct InlineMatrix - - template - struct Matrix : public MatrixBase - { - Matrix() - : MatrixBase() - { } - - Matrix(unsigned int rows, unsigned int cols) - : MatrixBase(rows, cols) - { } - - Matrix(unsigned int rows, unsigned int cols, Elem * values) - : MatrixBase(rows, cols, values) - { } - - Matrix(Matrix const& a) - : MatrixBase(a) - { } - - Matrix& operator=(Matrix const& a) - { - (MatrixBase::operator=)(a); - return *this; - } - - Matrix& operator+=(Matrix const& rhs) - { - addMatricesIP(rhs, *this); - return *this; - } - - Matrix& operator*=(Elem scale) - { - scaleMatrixIP(scale, *this); - return *this; - } - - Matrix operator+(Matrix const& rhs) const - { - Matrix res(this->num_rows(), this->num_cols()); - addMatrices(*this, rhs, res); - return res; - } - - Matrix operator-(Matrix const& rhs) const - { - Matrix res(this->num_rows(), this->num_cols()); - subtractMatrices(*this, rhs, res); - return res; - } - - }; // end struct Matrix - -//---------------------------------------------------------------------- - - typedef InlineVector Vector2f; - typedef InlineVector Vector2d; - typedef InlineVector Vector3f; - typedef InlineVector Vector3d; - typedef InlineVector Vector4f; - typedef InlineVector Vector4d; - - typedef InlineMatrix Matrix2x2f; - typedef InlineMatrix Matrix2x2d; - typedef InlineMatrix Matrix3x3f; - typedef InlineMatrix Matrix3x3d; - typedef InlineMatrix Matrix4x4f; - typedef InlineMatrix Matrix4x4d; - - typedef InlineMatrix Matrix2x3f; - typedef InlineMatrix Matrix2x3d; - typedef InlineMatrix Matrix3x4f; - typedef InlineMatrix Matrix3x4d; - - template - struct VectorArray - { - VectorArray(unsigned count, unsigned size) - : _count(count), _size(size), _values(0), _vectors(0) - { - unsigned const nTotal = _count * _size; - if (count > 0) _vectors = new Vector[count]; - if (nTotal > 0) _values = new Elem[nTotal]; - for (unsigned i = 0; i < _count; ++i) new (&_vectors[i]) Vector(_size, _values + i*_size); - } - - VectorArray(unsigned count, unsigned size, Elem initVal) - : _count(count), _size(size), _values(0), _vectors(0) - { - unsigned const nTotal = _count * _size; - if (count > 0) _vectors = new Vector[count]; - if (nTotal > 0) _values = new Elem[nTotal]; - for (unsigned i = 0; i < _count; ++i) new (&_vectors[i]) Vector(_size, _values + i*_size); - std::fill(_values, _values + nTotal, initVal); - } - - ~VectorArray() - { - delete [] _values; - delete [] _vectors; - } - - unsigned count() const { return _count; } - unsigned size() const { return _size; } - - //! Get the submatrix at position ix - Vector const& operator[](unsigned ix) const - { - return _vectors[ix]; - } - - //! Get the submatrix at position ix - Vector& operator[](unsigned ix) - { - return _vectors[ix]; - } - - protected: - unsigned _count, _size; - Elem * _values; - Vector * _vectors; - - private: - VectorArray(VectorArray const&); - void operator=(VectorArray const&); - }; - - template - struct MatrixArray - { - MatrixArray(unsigned count, unsigned nRows, unsigned nCols) - : _count(count), _rows(nRows), _columns(nCols), _values(0), _matrices(0) - { - unsigned const nTotal = _count * _rows * _columns; - if (count > 0) _matrices = new Matrix[count]; - if (nTotal > 0) _values = new double[nTotal]; - for (unsigned i = 0; i < _count; ++i) - new (&_matrices[i]) Matrix(_rows, _columns, _values + i*(_rows*_columns)); - } - - ~MatrixArray() - { - delete [] _matrices; - delete [] _values; - } - - //! Get the submatrix at position ix - Matrix const& operator[](unsigned ix) const - { - return _matrices[ix]; - } - - //! Get the submatrix at position ix - Matrix& operator[](unsigned ix) - { - return _matrices[ix]; - } - - unsigned count() const { return _count; } - unsigned num_rows() const { return _rows; } - unsigned num_cols() const { return _columns; } - - protected: - unsigned _count, _rows, _columns; - double * _values; - Matrix * _matrices; - - private: - MatrixArray(MatrixArray const&); - void operator=(MatrixArray const&); - }; - -//---------------------------------------------------------------------- - - template - inline InlineVector - operator+(InlineVector const& v, InlineVector const& w) - { - InlineVector res; - addVectors(v, w, res); - return res; - } - - template - inline InlineVector - operator-(InlineVector const& v, InlineVector const& w) - { - InlineVector res; - subtractVectors(v, w, res); - return res; - } - - template - inline InlineVector - operator*(Elem scale, InlineVector const& v) - { - InlineVector res; - scaleVector(scale, v, res); - return res; - } - - template - inline InlineVector - operator*(InlineMatrix const& A, InlineVector const& v) - { - InlineVector res; - multiply_A_v(A, v, res); - return res; - } - - template - inline InlineMatrix - operator*(InlineMatrix const& A, InlineMatrix const& B) - { - InlineMatrix res; - multiply_A_B(A, B, res); - return res; - } - - template - inline InlineMatrix - transposedMatrix(InlineMatrix const& A) - { - InlineMatrix At; - makeTransposedMatrix(A, At); - return At; - } - - template - inline InlineMatrix - invertedMatrix(InlineMatrix const& A) - { - Elem a = A[0][0], b = A[0][1], c = A[0][2]; - Elem d = A[1][0], e = A[1][1], f = A[1][2]; - Elem g = A[2][0], h = A[2][1], i = A[2][2]; - - Elem const det = a*e*i + b*f*g + c*d*h - c*e*g - b*d*i - a*f*h; - - InlineMatrix res; - res[0][0] = e*i-f*h; res[0][1] = c*h-b*i; res[0][2] = b*f-c*e; - res[1][0] = f*g-d*i; res[1][1] = a*i-c*g; res[1][2] = c*d-a*f; - res[2][0] = d*h-e*g; res[2][1] = b*g-a*h; res[2][2] = a*e-b*d; - - scaleMatrixIP(1.0/det, res); - return res; - } - - template - inline InlineVector - makeVector2(Elem a, Elem b) - { - InlineVector res; - res[0] = a; res[1] = b; - return res; - } - - template - inline InlineVector - makeVector3(Elem a, Elem b, Elem c) - { - InlineVector res; - res[0] = a; res[1] = b; res[2] = c; - return res; - } - - template - inline void - displayVector(Vec const& v) - { - using namespace std; - - for (int r = 0; r < v.size(); ++r) - cout << v[r] << " "; - cout << endl; - } - - template - inline void - displayMatrix(Mat const& A) - { - using namespace std; - - for (int r = 0; r < A.num_rows(); ++r) - { - for (int c = 0; c < A.num_cols(); ++c) - cout << A[r][c] << " "; - cout << endl; - } - } - -} // end namespace V3D - -#endif diff --git a/extern/libmv/third_party/ssba/Math/v3d_mathutilities.h b/extern/libmv/third_party/ssba/Math/v3d_mathutilities.h deleted file mode 100644 index 9e38b92a94b..00000000000 --- a/extern/libmv/third_party/ssba/Math/v3d_mathutilities.h +++ /dev/null @@ -1,59 +0,0 @@ -// -*- C++ -*- -/* -Copyright (c) 2008 University of North Carolina at Chapel Hill - -This file is part of SSBA (Simple Sparse Bundle Adjustment). - -SSBA is free software: you can redistribute it and/or modify it under the -terms of the GNU Lesser General Public License as published by the Free -Software Foundation, either version 3 of the License, or (at your option) any -later version. - -SSBA is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. - -You should have received a copy of the GNU Lesser General Public License along -with SSBA. If not, see . -*/ - -#ifndef V3D_MATH_UTILITIES_H -#define V3D_MATH_UTILITIES_H - -#include "Math/v3d_linear.h" -#include "Math/v3d_linear_utils.h" - -#include - -namespace V3D -{ - - template - inline void - createRotationMatrixRodriguez(Vec const& omega, Mat& R) - { - assert(omega.size() == 3); - assert(R.num_rows() == 3); - assert(R.num_cols() == 3); - - double const theta = norm_L2(omega); - makeIdentityMatrix(R); - if (fabs(theta) > 1e-6) - { - Matrix3x3d J, J2; - makeCrossProductMatrix(omega, J); - multiply_A_B(J, J, J2); - double const c1 = sin(theta)/theta; - double const c2 = (1-cos(theta))/(theta*theta); - for (int i = 0; i < 3; ++i) - for (int j = 0; j < 3; ++j) - R[i][j] += c1*J[i][j] + c2*J2[i][j]; - } - } // end createRotationMatrixRodriguez() - - template inline double sqr(T x) { return x*x; } - -} // namespace V3D - -#endif diff --git a/extern/libmv/third_party/ssba/Math/v3d_optimization.cpp b/extern/libmv/third_party/ssba/Math/v3d_optimization.cpp deleted file mode 100644 index 234815fcd1f..00000000000 --- a/extern/libmv/third_party/ssba/Math/v3d_optimization.cpp +++ /dev/null @@ -1,955 +0,0 @@ -/* -Copyright (c) 2008 University of North Carolina at Chapel Hill - -This file is part of SSBA (Simple Sparse Bundle Adjustment). - -SSBA is free software: you can redistribute it and/or modify it under the -terms of the GNU Lesser General Public License as published by the Free -Software Foundation, either version 3 of the License, or (at your option) any -later version. - -SSBA is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. - -You should have received a copy of the GNU Lesser General Public License along -with SSBA. If not, see . -*/ - -#include "Math/v3d_optimization.h" - -#if defined(V3DLIB_ENABLE_SUITESPARSE) -//# include "COLAMD/Include/colamd.h" -# include "colamd.h" -extern "C" -{ -//# include "LDL/Include/ldl.h" -# include "ldl.h" -} -#endif - -#include -#include - -#define USE_BLOCK_REORDERING 1 -#define USE_MULTIPLICATIVE_UPDATE 1 - -using namespace std; - -namespace -{ - - using namespace V3D; - - inline double - squaredResidual(VectorArray const& e) - { - int const N = e.count(); - int const M = e.size(); - - double res = 0.0; - - for (int n = 0; n < N; ++n) - for (int m = 0; m < M; ++m) - res += e[n][m] * e[n][m]; - - return res; - } // end squaredResidual() - -} // end namespace <> - -namespace V3D -{ - - int optimizerVerbosenessLevel = 0; - -#if defined(V3DLIB_ENABLE_SUITESPARSE) - - void - SparseLevenbergOptimizer::setupSparseJtJ() - { - int const nVaryingA = _nParametersA - _nNonvaryingA; - int const nVaryingB = _nParametersB - _nNonvaryingB; - int const nVaryingC = _paramDimensionC - _nNonvaryingC; - - int const bColumnStart = nVaryingA*_paramDimensionA; - int const cColumnStart = bColumnStart + nVaryingB*_paramDimensionB; - int const nColumns = cColumnStart + nVaryingC; - - _jointNonzerosW.clear(); - _jointIndexW.resize(_nMeasurements); -#if 1 - { - map, int> jointNonzeroMap; - for (size_t k = 0; k < _nMeasurements; ++k) - { - int const i = _correspondingParamA[k] - _nNonvaryingA; - int const j = _correspondingParamB[k] - _nNonvaryingB; - if (i >= 0 && j >= 0) - { - map, int>::const_iterator p = jointNonzeroMap.find(make_pair(i, j)); - if (p == jointNonzeroMap.end()) - { - jointNonzeroMap.insert(make_pair(make_pair(i, j), _jointNonzerosW.size())); - _jointIndexW[k] = _jointNonzerosW.size(); - _jointNonzerosW.push_back(make_pair(i, j)); - } - else - { - _jointIndexW[k] = (*p).second; - } // end if - } // end if - } // end for (k) - } // end scope -#else - for (size_t k = 0; k < _nMeasurements; ++k) - { - int const i = _correspondingParamA[k] - _nNonvaryingA; - int const j = _correspondingParamB[k] - _nNonvaryingB; - if (i >= 0 && j >= 0) - { - _jointIndexW[k] = _jointNonzerosW.size(); - _jointNonzerosW.push_back(make_pair(i, j)); - } - } // end for (k) -#endif - -#if defined(USE_BLOCK_REORDERING) - int const bBlockColumnStart = nVaryingA; - int const cBlockColumnStart = bBlockColumnStart + nVaryingB; - - int const nBlockColumns = cBlockColumnStart + ((nVaryingC > 0) ? 1 : 0); - - //cout << "nBlockColumns = " << nBlockColumns << endl; - - // For the column reordering we treat the columns belonging to one set - // of parameters as one (logical) column. - - // Determine non-zeros of JtJ (we forget about the non-zero diagonal for now) - // Only consider nonzeros of Ai^t * Bj induced by the measurements. - vector > nz_blockJtJ(_jointNonzerosW.size()); - for (int k = 0; k < _jointNonzerosW.size(); ++k) - { - nz_blockJtJ[k].first = _jointNonzerosW[k].second + bBlockColumnStart; - nz_blockJtJ[k].second = _jointNonzerosW[k].first; - } - - if (nVaryingC > 0) - { - // We assume, that the global unknowns are linked to every other variable. - for (int i = 0; i < nVaryingA; ++i) - nz_blockJtJ.push_back(make_pair(cBlockColumnStart, i)); - for (int j = 0; j < nVaryingB; ++j) - nz_blockJtJ.push_back(make_pair(cBlockColumnStart, j + bBlockColumnStart)); - } // end if - - int const nnzBlock = nz_blockJtJ.size(); - - vector permBlockJtJ(nBlockColumns + 1); - - if (nnzBlock > 0) - { -// cout << "nnzBlock = " << nnzBlock << endl; - - CCS_Matrix blockJtJ(nBlockColumns, nBlockColumns, nz_blockJtJ); - -// cout << " nz_blockJtJ: " << endl; -// for (size_t k = 0; k < nz_blockJtJ.size(); ++k) -// cout << " " << nz_blockJtJ[k].first << ":" << nz_blockJtJ[k].second << endl; -// cout << endl; - - int * colStarts = (int *)blockJtJ.getColumnStarts(); - int * rowIdxs = (int *)blockJtJ.getRowIndices(); - -// cout << "blockJtJ_colStarts = "; -// for (int k = 0; k <= nBlockColumns; ++k) cout << colStarts[k] << " "; -// cout << endl; - -// cout << "blockJtJ_rowIdxs = "; -// for (int k = 0; k < nnzBlock; ++k) cout << rowIdxs[k] << " "; -// cout << endl; - - int stats[COLAMD_STATS]; - symamd(nBlockColumns, rowIdxs, colStarts, &permBlockJtJ[0], (double *) NULL, stats, &calloc, &free); - if (optimizerVerbosenessLevel >= 2) symamd_report(stats); - } - else - { - for (int k = 0; k < permBlockJtJ.size(); ++k) permBlockJtJ[k] = k; - } // end if - -// cout << "permBlockJtJ = "; -// for (int k = 0; k < permBlockJtJ.size(); ++k) -// cout << permBlockJtJ[k] << " "; -// cout << endl; - - // From the determined symbolic permutation with logical variables, determine the actual ordering - _perm_JtJ.resize(nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB + nVaryingC + 1); - - int curDstCol = 0; - for (int k = 0; k < permBlockJtJ.size()-1; ++k) - { - int const srcCol = permBlockJtJ[k]; - if (srcCol < nVaryingA) - { - for (int n = 0; n < _paramDimensionA; ++n) - _perm_JtJ[curDstCol + n] = srcCol*_paramDimensionA + n; - curDstCol += _paramDimensionA; - } - else if (srcCol >= bBlockColumnStart && srcCol < cBlockColumnStart) - { - int const bStart = nVaryingA*_paramDimensionA; - int const j = srcCol - bBlockColumnStart; - - for (int n = 0; n < _paramDimensionB; ++n) - _perm_JtJ[curDstCol + n] = bStart + j*_paramDimensionB + n; - curDstCol += _paramDimensionB; - } - else if (srcCol == cBlockColumnStart) - { - int const cStart = nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB; - - for (int n = 0; n < nVaryingC; ++n) - _perm_JtJ[curDstCol + n] = cStart + n; - curDstCol += nVaryingC; - } - else - { - cerr << "Should not reach " << __LINE__ << ":" << __LINE__ << "!" << endl; - assert(false); - } - } -#else - vector > nz, nzL; - this->serializeNonZerosJtJ(nz); - - for (int k = 0; k < nz.size(); ++k) - { - // Swap rows and columns, since serializeNonZerosJtJ() generates the - // upper triangular part but symamd wants the lower triangle. - nzL.push_back(make_pair(nz[k].second, nz[k].first)); - } - - _perm_JtJ.resize(nColumns+1); - - if (nzL.size() > 0) - { - CCS_Matrix symbJtJ(nColumns, nColumns, nzL); - - int * colStarts = (int *)symbJtJ.getColumnStarts(); - int * rowIdxs = (int *)symbJtJ.getRowIndices(); - -// cout << "symbJtJ_colStarts = "; -// for (int k = 0; k <= nColumns; ++k) cout << colStarts[k] << " "; -// cout << endl; - -// cout << "symbJtJ_rowIdxs = "; -// for (int k = 0; k < nzL.size(); ++k) cout << rowIdxs[k] << " "; -// cout << endl; - - int stats[COLAMD_STATS]; - symamd(nColumns, rowIdxs, colStarts, &_perm_JtJ[0], (double *) NULL, stats, &calloc, &free); - if (optimizerVerbosenessLevel >= 2) symamd_report(stats); - } - else - { - for (int k = 0; k < _perm_JtJ.size(); ++k) _perm_JtJ[k] = k; - } //// end if -#endif - _perm_JtJ.back() = _perm_JtJ.size() - 1; - -// cout << "_perm_JtJ = "; -// for (int k = 0; k < _perm_JtJ.size(); ++k) cout << _perm_JtJ[k] << " "; -// cout << endl; - - // Finally, compute the inverse of the full permutation. - _invPerm_JtJ.resize(_perm_JtJ.size()); - for (size_t k = 0; k < _perm_JtJ.size(); ++k) - _invPerm_JtJ[_perm_JtJ[k]] = k; - - vector > nz_JtJ; - this->serializeNonZerosJtJ(nz_JtJ); - - for (int k = 0; k < nz_JtJ.size(); ++k) - { - int const i = nz_JtJ[k].first; - int const j = nz_JtJ[k].second; - - int pi = _invPerm_JtJ[i]; - int pj = _invPerm_JtJ[j]; - // Swap values if in lower triangular part - if (pi > pj) std::swap(pi, pj); - nz_JtJ[k].first = pi; - nz_JtJ[k].second = pj; - } - - int const nnz = nz_JtJ.size(); - -// cout << "nz_JtJ = "; -// for (int k = 0; k < nnz; ++k) cout << nz_JtJ[k].first << ":" << nz_JtJ[k].second << " "; -// cout << endl; - - _JtJ.create(nColumns, nColumns, nz_JtJ); - -// cout << "_colStart_JtJ = "; -// for (int k = 0; k < _JtJ.num_cols(); ++k) cout << _JtJ.getColumnStarts()[k] << " "; -// cout << endl; - -// cout << "_rowIdxs_JtJ = "; -// for (int k = 0; k < nnz; ++k) cout << _JtJ.getRowIndices()[k] << " "; -// cout << endl; - - vector workFlags(nColumns); - - _JtJ_Lp.resize(nColumns+1); - _JtJ_Parent.resize(nColumns); - _JtJ_Lnz.resize(nColumns); - - ldl_symbolic(nColumns, (int *)_JtJ.getColumnStarts(), (int *)_JtJ.getRowIndices(), - &_JtJ_Lp[0], &_JtJ_Parent[0], &_JtJ_Lnz[0], - &workFlags[0], NULL, NULL); - - if (optimizerVerbosenessLevel >= 1) - cout << "SparseLevenbergOptimizer: Nonzeros in LDL decomposition: " << _JtJ_Lp[nColumns] << endl; - - } // end SparseLevenbergOptimizer::setupSparseJtJ() - - void - SparseLevenbergOptimizer::serializeNonZerosJtJ(vector >& dst) const - { - int const nVaryingA = _nParametersA - _nNonvaryingA; - int const nVaryingB = _nParametersB - _nNonvaryingB; - int const nVaryingC = _paramDimensionC - _nNonvaryingC; - - int const bColumnStart = nVaryingA*_paramDimensionA; - int const cColumnStart = bColumnStart + nVaryingB*_paramDimensionB; - - dst.clear(); - - // Add the diagonal block matrices (only the upper triangular part). - - // Ui submatrices of JtJ - for (int i = 0; i < nVaryingA; ++i) - { - int const i0 = i * _paramDimensionA; - - for (int c = 0; c < _paramDimensionA; ++c) - for (int r = 0; r <= c; ++r) - dst.push_back(make_pair(i0 + r, i0 + c)); - } - - // Vj submatrices of JtJ - for (int j = 0; j < nVaryingB; ++j) - { - int const j0 = j*_paramDimensionB + bColumnStart; - - for (int c = 0; c < _paramDimensionB; ++c) - for (int r = 0; r <= c; ++r) - dst.push_back(make_pair(j0 + r, j0 + c)); - } - - // Z submatrix of JtJ - for (int c = 0; c < nVaryingC; ++c) - for (int r = 0; r <= c; ++r) - dst.push_back(make_pair(cColumnStart + r, cColumnStart + c)); - - // Add the elements i and j linked by an observation k - // W submatrix of JtJ - for (size_t n = 0; n < _jointNonzerosW.size(); ++n) - { - int const i0 = _jointNonzerosW[n].first; - int const j0 = _jointNonzerosW[n].second; - int const r0 = i0*_paramDimensionA; - int const c0 = j0*_paramDimensionB + bColumnStart; - - for (int r = 0; r < _paramDimensionA; ++r) - for (int c = 0; c < _paramDimensionB; ++c) - dst.push_back(make_pair(r0 + r, c0 + c)); - } // end for (n) - - if (nVaryingC > 0) - { - // Finally, add the dense columns linking i (resp. j) with the global parameters. - // X submatrix of JtJ - for (int i = 0; i < nVaryingA; ++i) - { - int const i0 = i*_paramDimensionA; - - for (int r = 0; r < _paramDimensionA; ++r) - for (int c = 0; c < nVaryingC; ++c) - dst.push_back(make_pair(i0 + r, cColumnStart + c)); - } - - // Y submatrix of JtJ - for (int j = 0; j < nVaryingB; ++j) - { - int const j0 = j*_paramDimensionB + bColumnStart; - - for (int r = 0; r < _paramDimensionB; ++r) - for (int c = 0; c < nVaryingC; ++c) - dst.push_back(make_pair(j0 + r, cColumnStart + c)); - } - } // end if - } // end SparseLevenbergOptimizer::serializeNonZerosJtJ() - - void - SparseLevenbergOptimizer::fillSparseJtJ(MatrixArray const& Ui, - MatrixArray const& Vj, - MatrixArray const& Wn, - Matrix const& Z, - Matrix const& X, - Matrix const& Y) - { - int const nVaryingA = _nParametersA - _nNonvaryingA; - int const nVaryingB = _nParametersB - _nNonvaryingB; - int const nVaryingC = _paramDimensionC - _nNonvaryingC; - - int const bColumnStart = nVaryingA*_paramDimensionA; - int const cColumnStart = bColumnStart + nVaryingB*_paramDimensionB; - - int const nCols = _JtJ.num_cols(); - int const nnz = _JtJ.getNonzeroCount(); - - // The following has to replicate the procedure as in serializeNonZerosJtJ() - - int serial = 0; - - double * values = _JtJ.getValues(); - int const * destIdxs = _JtJ.getDestIndices(); - - // Add the diagonal block matrices (only the upper triangular part). - - // Ui submatrices of JtJ - for (int i = 0; i < nVaryingA; ++i) - { - int const i0 = i * _paramDimensionA; - - for (int c = 0; c < _paramDimensionA; ++c) - for (int r = 0; r <= c; ++r, ++serial) - values[destIdxs[serial]] = Ui[i][r][c]; - } - - // Vj submatrices of JtJ - for (int j = 0; j < nVaryingB; ++j) - { - int const j0 = j*_paramDimensionB + bColumnStart; - - for (int c = 0; c < _paramDimensionB; ++c) - for (int r = 0; r <= c; ++r, ++serial) - values[destIdxs[serial]] = Vj[j][r][c]; - } - - // Z submatrix of JtJ - for (int c = 0; c < nVaryingC; ++c) - for (int r = 0; r <= c; ++r, ++serial) - values[destIdxs[serial]] = Z[r][c]; - - // Add the elements i and j linked by an observation k - // W submatrix of JtJ - for (size_t n = 0; n < _jointNonzerosW.size(); ++n) - { - for (int r = 0; r < _paramDimensionA; ++r) - for (int c = 0; c < _paramDimensionB; ++c, ++serial) - values[destIdxs[serial]] = Wn[n][r][c]; - } // end for (k) - - if (nVaryingC > 0) - { - // Finally, add the dense columns linking i (resp. j) with the global parameters. - // X submatrix of JtJ - for (int i = 0; i < nVaryingA; ++i) - { - int const r0 = i * _paramDimensionA; - for (int r = 0; r < _paramDimensionA; ++r) - for (int c = 0; c < nVaryingC; ++c, ++serial) - values[destIdxs[serial]] = X[r0+r][c]; - } - - // Y submatrix of JtJ - for (int j = 0; j < nVaryingB; ++j) - { - int const r0 = j * _paramDimensionB; - for (int r = 0; r < _paramDimensionB; ++r) - for (int c = 0; c < nVaryingC; ++c, ++serial) - values[destIdxs[serial]] = Y[r0+r][c]; - } - } // end if - } // end SparseLevenbergOptimizer::fillSparseJtJ() - - void - SparseLevenbergOptimizer::minimize() - { - status = LEVENBERG_OPTIMIZER_TIMEOUT; - bool computeDerivatives = true; - - int const nVaryingA = _nParametersA - _nNonvaryingA; - int const nVaryingB = _nParametersB - _nNonvaryingB; - int const nVaryingC = _paramDimensionC - _nNonvaryingC; - - if (nVaryingA == 0 && nVaryingB == 0 && nVaryingC == 0) - { - // No degrees of freedom, nothing to optimize. - status = LEVENBERG_OPTIMIZER_CONVERGED; - return; - } - - this->setupSparseJtJ(); - - Vector weights(_nMeasurements); - - MatrixArray Ak(_nMeasurements, _measurementDimension, _paramDimensionA); - MatrixArray Bk(_nMeasurements, _measurementDimension, _paramDimensionB); - MatrixArray Ck(_nMeasurements, _measurementDimension, _paramDimensionC); - - MatrixArray Ui(nVaryingA, _paramDimensionA, _paramDimensionA); - MatrixArray Vj(nVaryingB, _paramDimensionB, _paramDimensionB); - - // Wn = Ak^t*Bk - MatrixArray Wn(_jointNonzerosW.size(), _paramDimensionA, _paramDimensionB); - - Matrix Z(nVaryingC, nVaryingC); - - // X = A^t*C - Matrix X(nVaryingA*_paramDimensionA, nVaryingC); - // Y = B^t*C - Matrix Y(nVaryingB*_paramDimensionB, nVaryingC); - - VectorArray residuals(_nMeasurements, _measurementDimension); - VectorArray residuals2(_nMeasurements, _measurementDimension); - - VectorArray diagUi(nVaryingA, _paramDimensionA); - VectorArray diagVj(nVaryingB, _paramDimensionB); - Vector diagZ(nVaryingC); - - VectorArray At_e(nVaryingA, _paramDimensionA); - VectorArray Bt_e(nVaryingB, _paramDimensionB); - Vector Ct_e(nVaryingC); - - Vector Jt_e(nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB + nVaryingC); - - Vector delta(nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB + nVaryingC); - Vector deltaPerm(nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB + nVaryingC); - - VectorArray deltaAi(_nParametersA, _paramDimensionA); - VectorArray deltaBj(_nParametersB, _paramDimensionB); - Vector deltaC(_paramDimensionC); - - double err = 0.0; - - for (currentIteration = 0; currentIteration < maxIterations; ++currentIteration) - { - if (optimizerVerbosenessLevel >= 2) - cout << "SparseLevenbergOptimizer: currentIteration: " << currentIteration << endl; - if (computeDerivatives) - { - this->evalResidual(residuals); - this->fillWeights(residuals, weights); - for (int k = 0; k < _nMeasurements; ++k) - scaleVectorIP(weights[k], residuals[k]); - - err = squaredResidual(residuals); - - if (optimizerVerbosenessLevel >= 1) cout << "SparseLevenbergOptimizer: |residual|^2 = " << err << endl; - if (optimizerVerbosenessLevel >= 2) cout << "SparseLevenbergOptimizer: lambda = " << lambda << endl; - - for (int k = 0; k < residuals.count(); ++k) scaleVectorIP(-1.0, residuals[k]); - - this->setupJacobianGathering(); - this->fillAllJacobians(weights, Ak, Bk, Ck); - - // Compute the different parts of J^t*e - if (nVaryingA > 0) - { - for (int i = 0; i < nVaryingA; ++i) makeZeroVector(At_e[i]); - - Vector tmp(_paramDimensionA); - - for (int k = 0; k < _nMeasurements; ++k) - { - int const i = _correspondingParamA[k] - _nNonvaryingA; - if (i < 0) continue; - multiply_At_v(Ak[k], residuals[k], tmp); - addVectors(tmp, At_e[i], At_e[i]); - } // end for (k) - } // end if - - if (nVaryingB > 0) - { - for (int j = 0; j < nVaryingB; ++j) makeZeroVector(Bt_e[j]); - - Vector tmp(_paramDimensionB); - - for (int k = 0; k < _nMeasurements; ++k) - { - int const j = _correspondingParamB[k] - _nNonvaryingB; - if (j < 0) continue; - multiply_At_v(Bk[k], residuals[k], tmp); - addVectors(tmp, Bt_e[j], Bt_e[j]); - } // end for (k) - } // end if - - if (nVaryingC > 0) - { - makeZeroVector(Ct_e); - - Vector tmp(_paramDimensionC); - - for (int k = 0; k < _nMeasurements; ++k) - { - multiply_At_v(Ck[k], residuals[k], tmp); - for (int l = 0; l < nVaryingC; ++l) Ct_e[l] += tmp[_nNonvaryingC + l]; - } - } // end if - - int pos = 0; - for (int i = 0; i < nVaryingA; ++i) - for (int l = 0; l < _paramDimensionA; ++l, ++pos) - Jt_e[pos] = At_e[i][l]; - for (int j = 0; j < nVaryingB; ++j) - for (int l = 0; l < _paramDimensionB; ++l, ++pos) - Jt_e[pos] = Bt_e[j][l]; - for (int l = 0; l < nVaryingC; ++l, ++pos) - Jt_e[pos] = Ct_e[l]; - -// cout << "Jt_e = "; -// for (int k = 0; k < Jt_e.size(); ++k) cout << Jt_e[k] << " "; -// cout << endl; - - if (this->applyGradientStoppingCriteria(norm_Linf(Jt_e))) - { - status = LEVENBERG_OPTIMIZER_CONVERGED; - goto end; - } - - // The lhs J^t*J consists of several parts: - // [ U W X ] - // J^t*J = [ W^t V Y ] - // [ X^t Y^t Z ], - // where U, V and W are block-sparse matrices (due to the sparsity of A and B). - // X, Y and Z contain only a few columns (the number of global parameters). - - if (nVaryingA > 0) - { - // Compute Ui - Matrix U(_paramDimensionA, _paramDimensionA); - - for (int i = 0; i < nVaryingA; ++i) makeZeroMatrix(Ui[i]); - - for (int k = 0; k < _nMeasurements; ++k) - { - int const i = _correspondingParamA[k] - _nNonvaryingA; - if (i < 0) continue; - multiply_At_A(Ak[k], U); - addMatricesIP(U, Ui[i]); - } // end for (k) - } // end if - - if (nVaryingB > 0) - { - // Compute Vj - Matrix V(_paramDimensionB, _paramDimensionB); - - for (int j = 0; j < nVaryingB; ++j) makeZeroMatrix(Vj[j]); - - for (int k = 0; k < _nMeasurements; ++k) - { - int const j = _correspondingParamB[k] - _nNonvaryingB; - if (j < 0) continue; - multiply_At_A(Bk[k], V); - addMatricesIP(V, Vj[j]); - } // end for (k) - } // end if - - if (nVaryingC > 0) - { - Matrix ZZ(_paramDimensionC, _paramDimensionC); - Matrix Zsum(_paramDimensionC, _paramDimensionC); - - makeZeroMatrix(Zsum); - - for (int k = 0; k < _nMeasurements; ++k) - { - multiply_At_A(Ck[k], ZZ); - addMatricesIP(ZZ, Zsum); - } // end for (k) - - // Ignore the non-varying parameters - for (int i = 0; i < nVaryingC; ++i) - for (int j = 0; j < nVaryingC; ++j) - Z[i][j] = Zsum[i+_nNonvaryingC][j+_nNonvaryingC]; - } // end if - - if (nVaryingA > 0 && nVaryingB > 0) - { - for (int n = 0; n < Wn.count(); ++n) makeZeroMatrix(Wn[n]); - - Matrix W(_paramDimensionA, _paramDimensionB); - - for (int k = 0; k < _nMeasurements; ++k) - { - int const n = _jointIndexW[k]; - if (n >= 0) - { - int const i0 = _jointNonzerosW[n].first; - int const j0 = _jointNonzerosW[n].second; - - multiply_At_B(Ak[k], Bk[k], W); - addMatricesIP(W, Wn[n]); - } // end if - } // end for (k) - } // end if - - if (nVaryingA > 0 && nVaryingC > 0) - { - Matrix XX(_paramDimensionA, _paramDimensionC); - - makeZeroMatrix(X); - - for (int k = 0; k < _nMeasurements; ++k) - { - int const i = _correspondingParamA[k] - _nNonvaryingA; - // Ignore the non-varying parameters - if (i < 0) continue; - - multiply_At_B(Ak[k], Ck[k], XX); - - for (int r = 0; r < _paramDimensionA; ++r) - for (int c = 0; c < nVaryingC; ++c) - X[r+i*_paramDimensionA][c] += XX[r][c+_nNonvaryingC]; - } // end for (k) - } // end if - - if (nVaryingB > 0 && nVaryingC > 0) - { - Matrix YY(_paramDimensionB, _paramDimensionC); - - makeZeroMatrix(Y); - - for (int k = 0; k < _nMeasurements; ++k) - { - int const j = _correspondingParamB[k] - _nNonvaryingB; - // Ignore the non-varying parameters - if (j < 0) continue; - - multiply_At_B(Bk[k], Ck[k], YY); - - for (int r = 0; r < _paramDimensionB; ++r) - for (int c = 0; c < nVaryingC; ++c) - Y[r+j*_paramDimensionB][c] += YY[r][c+_nNonvaryingC]; - } // end for (k) - } // end if - - if (currentIteration == 0) - { - // Initialize lambda as tau*max(JtJ[i][i]) - double maxEl = -1e30; - if (nVaryingA > 0) - { - for (int i = 0; i < nVaryingA; ++i) - for (int l = 0; l < _paramDimensionA; ++l) - maxEl = std::max(maxEl, Ui[i][l][l]); - } - if (nVaryingB > 0) - { - for (int j = 0; j < nVaryingB; ++j) - for (int l = 0; l < _paramDimensionB; ++l) - maxEl = std::max(maxEl, Vj[j][l][l]); - } - if (nVaryingC > 0) - { - for (int l = 0; l < nVaryingC; ++l) - maxEl = std::max(maxEl, Z[l][l]); - } - - lambda = tau * maxEl; - if (optimizerVerbosenessLevel >= 2) - cout << "SparseLevenbergOptimizer: initial lambda = " << lambda << endl; - } // end if (currentIteration == 0) - } // end if (computeDerivatives) - - for (int i = 0; i < nVaryingA; ++i) - { - for (int l = 0; l < _paramDimensionA; ++l) diagUi[i][l] = Ui[i][l][l]; - } // end for (i) - - for (int j = 0; j < nVaryingB; ++j) - { - for (int l = 0; l < _paramDimensionB; ++l) diagVj[j][l] = Vj[j][l][l]; - } // end for (j) - - for (int l = 0; l < nVaryingC; ++l) diagZ[l] = Z[l][l]; - - // Augment the diagonals with lambda (either by the standard additive update or by multiplication). -#if !defined(USE_MULTIPLICATIVE_UPDATE) - for (int i = 0; i < nVaryingA; ++i) - for (unsigned l = 0; l < _paramDimensionA; ++l) - Ui[i][l][l] += lambda; - - for (int j = 0; j < nVaryingB; ++j) - for (unsigned l = 0; l < _paramDimensionB; ++l) - Vj[j][l][l] += lambda; - - for (unsigned l = 0; l < nVaryingC; ++l) - Z[l][l] += lambda; -#else - for (int i = 0; i < nVaryingA; ++i) - for (unsigned l = 0; l < _paramDimensionA; ++l) - Ui[i][l][l] = std::max(Ui[i][l][l] * (1.0 + lambda), 1e-15); - - for (int j = 0; j < nVaryingB; ++j) - for (unsigned l = 0; l < _paramDimensionB; ++l) - Vj[j][l][l] = std::max(Vj[j][l][l] * (1.0 + lambda), 1e-15); - - for (unsigned l = 0; l < nVaryingC; ++l) - Z[l][l] = std::max(Z[l][l] * (1.0 + lambda), 1e-15); -#endif - - this->fillSparseJtJ(Ui, Vj, Wn, Z, X, Y); - - bool success = true; - double rho = 0.0; - { - int const nCols = _JtJ_Parent.size(); - int const nnz = _JtJ.getNonzeroCount(); - int const lnz = _JtJ_Lp.back(); - - vector Li(lnz); - vector Lx(lnz); - vector D(nCols), Y(nCols); - vector workPattern(nCols), workFlag(nCols); - - int * colStarts = (int *)_JtJ.getColumnStarts(); - int * rowIdxs = (int *)_JtJ.getRowIndices(); - double * values = _JtJ.getValues(); - - int const d = ldl_numeric(nCols, colStarts, rowIdxs, values, - &_JtJ_Lp[0], &_JtJ_Parent[0], &_JtJ_Lnz[0], - &Li[0], &Lx[0], &D[0], - &Y[0], &workPattern[0], &workFlag[0], - NULL, NULL); - - if (d == nCols) - { - ldl_perm(nCols, &deltaPerm[0], &Jt_e[0], &_perm_JtJ[0]); - ldl_lsolve(nCols, &deltaPerm[0], &_JtJ_Lp[0], &Li[0], &Lx[0]); - ldl_dsolve(nCols, &deltaPerm[0], &D[0]); - ldl_ltsolve(nCols, &deltaPerm[0], &_JtJ_Lp[0], &Li[0], &Lx[0]); - ldl_permt(nCols, &delta[0], &deltaPerm[0], &_perm_JtJ[0]); - } - else - { - if (optimizerVerbosenessLevel >= 2) - cout << "SparseLevenbergOptimizer: LDL decomposition failed. Increasing lambda." << endl; - success = false; - } - } - - if (success) - { - double const deltaSqrLength = sqrNorm_L2(delta); - - if (optimizerVerbosenessLevel >= 2) - cout << "SparseLevenbergOptimizer: ||delta||^2 = " << deltaSqrLength << endl; - - double const paramLength = this->getParameterLength(); - if (this->applyUpdateStoppingCriteria(paramLength, sqrt(deltaSqrLength))) - { - status = LEVENBERG_OPTIMIZER_SMALL_UPDATE; - goto end; - } - - // Copy the updates from delta to the respective arrays - int pos = 0; - - for (int i = 0; i < _nNonvaryingA; ++i) makeZeroVector(deltaAi[i]); - for (int i = _nNonvaryingA; i < _nParametersA; ++i) - for (int l = 0; l < _paramDimensionA; ++l, ++pos) - deltaAi[i][l] = delta[pos]; - - for (int j = 0; j < _nNonvaryingB; ++j) makeZeroVector(deltaBj[j]); - for (int j = _nNonvaryingB; j < _nParametersB; ++j) - for (int l = 0; l < _paramDimensionB; ++l, ++pos) - deltaBj[j][l] = delta[pos]; - - makeZeroVector(deltaC); - for (int l = _nNonvaryingC; l < _paramDimensionC; ++l, ++pos) - deltaC[l] = delta[pos]; - - saveAllParameters(); - if (nVaryingA > 0) updateParametersA(deltaAi); - if (nVaryingB > 0) updateParametersB(deltaBj); - if (nVaryingC > 0) updateParametersC(deltaC); - - this->evalResidual(residuals2); - for (int k = 0; k < _nMeasurements; ++k) - scaleVectorIP(weights[k], residuals2[k]); - - double const newErr = squaredResidual(residuals2); - rho = err - newErr; - if (optimizerVerbosenessLevel >= 2) - cout << "SparseLevenbergOptimizer: |new residual|^2 = " << newErr << endl; - -#if !defined(USE_MULTIPLICATIVE_UPDATE) - double const denom1 = lambda * deltaSqrLength; -#else - double denom1 = 0.0f; - for (int i = _nNonvaryingA; i < _nParametersA; ++i) - for (int l = 0; l < _paramDimensionA; ++l) - denom1 += deltaAi[i][l] * deltaAi[i][l] * diagUi[i-_nNonvaryingA][l]; - - for (int j = _nNonvaryingB; j < _nParametersB; ++j) - for (int l = 0; l < _paramDimensionB; ++l) - denom1 += deltaBj[j][l] * deltaBj[j][l] * diagVj[j-_nNonvaryingB][l]; - - for (int l = _nNonvaryingC; l < _paramDimensionC; ++l) - denom1 += deltaC[l] * deltaC[l] * diagZ[l-_nNonvaryingC]; - - denom1 *= lambda; -#endif - double const denom2 = innerProduct(delta, Jt_e); - rho = rho / (denom1 + denom2); - if (optimizerVerbosenessLevel >= 2) - cout << "SparseLevenbergOptimizer: rho = " << rho - << " denom1 = " << denom1 << " denom2 = " << denom2 << endl; - } // end if (success) - - if (success && rho > 0) - { - if (optimizerVerbosenessLevel >= 2) - cout << "SparseLevenbergOptimizer: Improved solution - decreasing lambda." << endl; - // Improvement in the new solution - decreaseLambda(rho); - computeDerivatives = true; - } - else - { - if (optimizerVerbosenessLevel >= 2) - cout << "SparseLevenbergOptimizer: Inferior solution - increasing lambda." << endl; - restoreAllParameters(); - increaseLambda(); - computeDerivatives = false; - - // Restore diagonal elements in Ui, Vj and Z. - for (int i = 0; i < nVaryingA; ++i) - { - for (int l = 0; l < _paramDimensionA; ++l) Ui[i][l][l] = diagUi[i][l]; - } // end for (i) - - for (int j = 0; j < nVaryingB; ++j) - { - for (int l = 0; l < _paramDimensionB; ++l) Vj[j][l][l] = diagVj[j][l]; - } // end for (j) - - for (int l = 0; l < nVaryingC; ++l) Z[l][l] = diagZ[l]; - } // end if - } // end for - - end:; - if (optimizerVerbosenessLevel >= 2) - cout << "Leaving SparseLevenbergOptimizer::minimize()." << endl; - } // end SparseLevenbergOptimizer::minimize() - -#endif // defined(V3DLIB_ENABLE_SUITESPARSE) - -} // end namespace V3D diff --git a/extern/libmv/third_party/ssba/Math/v3d_optimization.h b/extern/libmv/third_party/ssba/Math/v3d_optimization.h deleted file mode 100644 index 27d2e12287f..00000000000 --- a/extern/libmv/third_party/ssba/Math/v3d_optimization.h +++ /dev/null @@ -1,273 +0,0 @@ -// -*- C++ -*- -/* -Copyright (c) 2008 University of North Carolina at Chapel Hill - -This file is part of SSBA (Simple Sparse Bundle Adjustment). - -SSBA is free software: you can redistribute it and/or modify it under the -terms of the GNU Lesser General Public License as published by the Free -Software Foundation, either version 3 of the License, or (at your option) any -later version. - -SSBA is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. - -You should have received a copy of the GNU Lesser General Public License along -with SSBA. If not, see . -*/ - -#ifndef V3D_OPTIMIZATION_H -#define V3D_OPTIMIZATION_H - -#include "Math/v3d_linear.h" -#include "Math/v3d_mathutilities.h" - -#include -#include - -namespace V3D -{ - - enum - { - LEVENBERG_OPTIMIZER_TIMEOUT = 0, - LEVENBERG_OPTIMIZER_SMALL_UPDATE = 1, - LEVENBERG_OPTIMIZER_CONVERGED = 2 - }; - - extern int optimizerVerbosenessLevel; - - struct LevenbergOptimizerCommon - { - LevenbergOptimizerCommon() - : status(LEVENBERG_OPTIMIZER_TIMEOUT), currentIteration(0), maxIterations(50), - tau(1e-3), lambda(1e-3), - gradientThreshold(1e-10), updateThreshold(1e-10), - _nu(2.0) - { } - virtual ~LevenbergOptimizerCommon() {} - - // See Madsen et al., "Methods for non-linear least squares problems." - virtual void increaseLambda() - { - lambda *= _nu; _nu *= 2.0; - } - - virtual void decreaseLambda(double const rho) - { - double const r = 2*rho - 1.0; - lambda *= std::max(1.0/3.0, 1 - r*r*r); - if (lambda < 1e-10) lambda = 1e-10; - _nu = 2; - } - - bool applyGradientStoppingCriteria(double maxGradient) const - { - return maxGradient < gradientThreshold; - } - - bool applyUpdateStoppingCriteria(double paramLength, double updateLength) const - { - return updateLength < updateThreshold * (paramLength + updateThreshold); - } - - int status; - int currentIteration, maxIterations; - double tau, lambda; - double gradientThreshold, updateThreshold; - - protected: - double _nu; - }; // end struct LevenbergOptimizerCommon - -# if defined(V3DLIB_ENABLE_SUITESPARSE) - - struct SparseLevenbergOptimizer : public LevenbergOptimizerCommon - { - SparseLevenbergOptimizer(int measurementDimension, - int nParametersA, int paramDimensionA, - int nParametersB, int paramDimensionB, - int paramDimensionC, - std::vector const& correspondingParamA, - std::vector const& correspondingParamB) - : LevenbergOptimizerCommon(), - _nMeasurements(correspondingParamA.size()), - _measurementDimension(measurementDimension), - _nParametersA(nParametersA), _paramDimensionA(paramDimensionA), - _nParametersB(nParametersB), _paramDimensionB(paramDimensionB), - _paramDimensionC(paramDimensionC), - _nNonvaryingA(0), _nNonvaryingB(0), _nNonvaryingC(0), - _correspondingParamA(correspondingParamA), - _correspondingParamB(correspondingParamB) - { - assert(correspondingParamA.size() == correspondingParamB.size()); - } - - ~SparseLevenbergOptimizer() { } - - void setNonvaryingCounts(int nNonvaryingA, int nNonvaryingB, int nNonvaryingC) - { - _nNonvaryingA = nNonvaryingA; - _nNonvaryingB = nNonvaryingB; - _nNonvaryingC = nNonvaryingC; - } - - void getNonvaryingCounts(int& nNonvaryingA, int& nNonvaryingB, int& nNonvaryingC) const - { - nNonvaryingA = _nNonvaryingA; - nNonvaryingB = _nNonvaryingB; - nNonvaryingC = _nNonvaryingC; - } - - void minimize(); - - virtual void evalResidual(VectorArray& residuals) = 0; - - virtual void fillWeights(VectorArray const& residuals, Vector& w) - { - (void)residuals; - std::fill(w.begin(), w.end(), 1.0); - } - - void fillAllJacobians(Vector const& w, - MatrixArray& Ak, - MatrixArray& Bk, - MatrixArray& Ck) - { - int const nVaryingA = _nParametersA - _nNonvaryingA; - int const nVaryingB = _nParametersB - _nNonvaryingB; - int const nVaryingC = _paramDimensionC - _nNonvaryingC; - - for (unsigned k = 0; k < _nMeasurements; ++k) - { - int const i = _correspondingParamA[k]; - int const j = _correspondingParamB[k]; - - if (i < _nNonvaryingA && j < _nNonvaryingB) continue; - - fillJacobians(Ak[k], Bk[k], Ck[k], i, j, k); - } // end for (k) - - if (nVaryingA > 0) - { - for (unsigned k = 0; k < _nMeasurements; ++k) - scaleMatrixIP(w[k], Ak[k]); - } - if (nVaryingB > 0) - { - for (unsigned k = 0; k < _nMeasurements; ++k) - scaleMatrixIP(w[k], Bk[k]); - } - if (nVaryingC > 0) - { - for (unsigned k = 0; k < _nMeasurements; ++k) - scaleMatrixIP(w[k], Ck[k]); - } - } // end fillAllJacobians() - - virtual void setupJacobianGathering() { } - - virtual void fillJacobians(Matrix& Ak, Matrix& Bk, Matrix& Ck, - int i, int j, int k) = 0; - - virtual double getParameterLength() const = 0; - - virtual void updateParametersA(VectorArray const& deltaAi) = 0; - virtual void updateParametersB(VectorArray const& deltaBj) = 0; - virtual void updateParametersC(Vector const& deltaC) = 0; - virtual void saveAllParameters() = 0; - virtual void restoreAllParameters() = 0; - - int currentIteration, maxIterations; - - protected: - void serializeNonZerosJtJ(std::vector >& dst) const; - void setupSparseJtJ(); - void fillSparseJtJ(MatrixArray const& Ui, MatrixArray const& Vj, MatrixArray const& Wk, - Matrix const& Z, Matrix const& X, Matrix const& Y); - - int const _nMeasurements, _measurementDimension; - int const _nParametersA, _paramDimensionA; - int const _nParametersB, _paramDimensionB; - int const _paramDimensionC; - - int _nNonvaryingA, _nNonvaryingB, _nNonvaryingC; - - std::vector const& _correspondingParamA; - std::vector const& _correspondingParamB; - - std::vector > _jointNonzerosW; - std::vector _jointIndexW; - - std::vector _JtJ_Lp, _JtJ_Parent, _JtJ_Lnz; - std::vector _perm_JtJ, _invPerm_JtJ; - - CCS_Matrix _JtJ; - }; // end struct SparseLevenbergOptimizer - - struct StdSparseLevenbergOptimizer : public SparseLevenbergOptimizer - { - StdSparseLevenbergOptimizer(int measurementDimension, - int nParametersA, int paramDimensionA, - int nParametersB, int paramDimensionB, - int paramDimensionC, - std::vector const& correspondingParamA, - std::vector const& correspondingParamB) - : SparseLevenbergOptimizer(measurementDimension, nParametersA, paramDimensionA, - nParametersB, paramDimensionB, paramDimensionC, - correspondingParamA, correspondingParamB), - curParametersA(nParametersA, paramDimensionA), savedParametersA(nParametersA, paramDimensionA), - curParametersB(nParametersB, paramDimensionB), savedParametersB(nParametersB, paramDimensionB), - curParametersC(paramDimensionC), savedParametersC(paramDimensionC) - { } - - virtual double getParameterLength() const - { - double res = 0.0; - for (int i = 0; i < _nParametersA; ++i) res += sqrNorm_L2(curParametersA[i]); - for (int j = 0; j < _nParametersB; ++j) res += sqrNorm_L2(curParametersB[j]); - res += sqrNorm_L2(curParametersC); - return sqrt(res); - } - - virtual void updateParametersA(VectorArray const& deltaAi) - { - for (int i = 0; i < _nParametersA; ++i) addVectors(deltaAi[i], curParametersA[i], curParametersA[i]); - } - - virtual void updateParametersB(VectorArray const& deltaBj) - { - for (int j = 0; j < _nParametersB; ++j) addVectors(deltaBj[j], curParametersB[j], curParametersB[j]); - } - - virtual void updateParametersC(Vector const& deltaC) - { - addVectors(deltaC, curParametersC, curParametersC); - } - - virtual void saveAllParameters() - { - for (int i = 0; i < _nParametersA; ++i) savedParametersA[i] = curParametersA[i]; - for (int j = 0; j < _nParametersB; ++j) savedParametersB[j] = curParametersB[j]; - savedParametersC = curParametersC; - } - - virtual void restoreAllParameters() - { - for (int i = 0; i < _nParametersA; ++i) curParametersA[i] = savedParametersA[i]; - for (int j = 0; j < _nParametersB; ++j) curParametersB[j] = savedParametersB[j]; - curParametersC = savedParametersC; - } - - VectorArray curParametersA, savedParametersA; - VectorArray curParametersB, savedParametersB; - Vector curParametersC, savedParametersC; - }; // end struct StdSparseLevenbergOptimizer - -# endif - -} // end namespace V3D - -#endif diff --git a/extern/libmv/third_party/ssba/README.TXT b/extern/libmv/third_party/ssba/README.TXT deleted file mode 100644 index 734962b1df8..00000000000 --- a/extern/libmv/third_party/ssba/README.TXT +++ /dev/null @@ -1,92 +0,0 @@ -Description - -This is an implementation of a sparse Levenberg-Marquardt optimization -procedure and several bundle adjustment modules based on it. There are three -versions of bundle adjustment: -1) Pure metric adjustment. Camera poses have 6 dof and 3D points have 3 dof. -2) Common, but adjustable intrinsic and distortion parameters. This is useful, - if the set of images are taken with the same camera under constant zoom - settings. -3) Variable intrinsics and distortion parameters for each view. This addresses - the "community photo collection" setting, where each image is captured with - a different camera and/or with varying zoom setting. - -There are two demo applications in the Apps directory, bundle_common and -bundle_varying, which correspond to item 2) and 3) above. - -The input data file for both applications is a text file with the following -numerical values: - -First, the number of 3D points, views and 2D measurements: - -Then, the values of the intrinsic matrix - [ fx skew cx ] -K = [ 0 fy cy ] - [ 0 0 1 ], -and the distortion parameters according to the convention of the Bouget -toolbox: - - - -For the bundle_varying application this is given times, one for each -camera/view. -Then the 3D point positions are given: - - - -Note: the point-ids need not to be exactly from 0 to M-1, any (unique) ids -will do. -The camera poses are given subsequently: - - <12 entries of the RT matrix> - -There is a lot of confusion how to specify the orientation of cameras. We use -projection matrix notation, i.e. P = K [R|T], and a 3D point X in world -coordinates is transformed into the camera coordinate system by XX=R*X+T. - -Finally, the 2d image measurements (given in pixels) are provided: - - 1 - -See the example in the Dataset folder. - - -Performance - -This software is able to perform successful loop closing for a video sequence -containing 1745 views, 37920 3D points and 627228 image measurements in about -16min on a 2.2 GHz Core 2. The footprint in memory was <700MB. - - -Requirements - -Solving the augmented normal equation in the LM optimizer is done with LDL, a -Cholsky like decomposition method for sparse matrices (see -http://www.cise.ufl.edu/research/sparse/ldl). The appropriate column -reordering is done with COLAMD (see -http://www.cise.ufl.edu/research/sparse/colamd). Both packages are licensed -under the GNU LGPL. - -This software was developed under Linux, but should compile equally well on -other operating systems. - --Christopher Zach (cmzach@cs.unc.edu) - -/* -Copyright (c) 2008 University of North Carolina at Chapel Hill - -This file is part of SSBA (Simple Sparse Bundle Adjustment). - -SSBA is free software: you can redistribute it and/or modify it under the -terms of the GNU Lesser General Public License as published by the Free -Software Foundation, either version 3 of the License, or (at your option) any -later version. - -SSBA is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. - -You should have received a copy of the GNU Lesser General Public License along -with SSBA. If not, see . -*/ diff --git a/extern/libmv/third_party/ssba/README.libmv b/extern/libmv/third_party/ssba/README.libmv deleted file mode 100644 index 45e0a31f6fc..00000000000 --- a/extern/libmv/third_party/ssba/README.libmv +++ /dev/null @@ -1,23 +0,0 @@ -Project: SSBA -URL: http://www.cs.unc.edu/~cmzach/opensource.html -License: LGPL3 -Upstream version: 1.0 - -Local modifications: - - * Added - SET(CMAKE_CXX_FLAGS "") - to CMakeLists.txt to prevent warnings from being treated as errors. - * Fixed "unused variable" in the header files. Warnings in the cpps files - are still there. - * Fixed a bug in CameraMatrix::opticalAxis() in file - Geometry/v3d_cameramatrix.h - * Deleted the Dataset directory. - * Added '#include ' to ssba/Apps/bundle_common.cpp and - ssba/Apps/bundle_varying.cpp to stop undefined references to strcmp - * Removed unnecessary elements from the CMakeLists.txt file, including the - obsoleted local_config.cmake and friends. - * Added a virtual destructor to V3D::LevenbergOptimizerCommon in - Math/v3d_optimization.h - * Added /EHsc WIN32-specific flag to CMakeLists.txt - * Remove unused variable Vector3d np in bundle_common.cpp and bundle_varying (in main() function). -- cgit v1.2.3 From 05a5cbbda2287ce89bbd3ce370008aabb319913f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 26 Feb 2013 11:46:27 +0000 Subject: Camera tracking: switch euclidean intersection code to use Ceres Would not expect any significant changes in solver behavior, but it could be more accurate in some cases. Switching projective intersection to ceres is marked as a TODO for now. --- extern/libmv/libmv/simple_pipeline/intersect.cc | 80 ++++++++++++++++--------- 1 file changed, 53 insertions(+), 27 deletions(-) (limited to 'extern') diff --git a/extern/libmv/libmv/simple_pipeline/intersect.cc b/extern/libmv/libmv/simple_pipeline/intersect.cc index 0c2f744dc1c..660b4b21ece 100644 --- a/extern/libmv/libmv/simple_pipeline/intersect.cc +++ b/extern/libmv/libmv/simple_pipeline/intersect.cc @@ -18,6 +18,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. +#include "libmv/simple_pipeline/intersect.h" + #include "libmv/base/vector.h" #include "libmv/logging/logging.h" #include "libmv/multiview/projection.h" @@ -26,39 +28,41 @@ #include "libmv/multiview/projection.h" #include "libmv/numeric/numeric.h" #include "libmv/numeric/levenberg_marquardt.h" -#include "libmv/simple_pipeline/intersect.h" #include "libmv/simple_pipeline/reconstruction.h" #include "libmv/simple_pipeline/tracks.h" +#include "ceres/ceres.h" + namespace libmv { namespace { -struct EuclideanIntersectCostFunction { +class EuclideanIntersectCostFunctor { public: - typedef Vec FMatrixType; - typedef Vec3 XMatrixType; + EuclideanIntersectCostFunctor(const Marker &marker, + const EuclideanCamera &camera) + : marker_(marker), camera_(camera) {} - EuclideanIntersectCostFunction(const vector &markers, - const EuclideanReconstruction &reconstruction) - : markers(markers), - reconstruction(reconstruction) {} + template + bool operator()(const T *X, T *residuals) const { + typedef Eigen::Matrix Mat3; + typedef Eigen::Matrix Vec3; - Vec operator()(const Vec3 &X) const { - Vec residuals(2 * markers.size()); - residuals.setZero(); - for (int i = 0; i < markers.size(); ++i) { - const EuclideanCamera &camera = - *reconstruction.CameraForImage(markers[i].image); - Vec3 projected = camera.R * X + camera.t; - projected /= projected(2); - residuals[2*i + 0] = projected(0) - markers[i].x; - residuals[2*i + 1] = projected(1) - markers[i].y; - } - return residuals; + Vec3 x(X); + Mat3 R(camera_.R.cast()); + Vec3 t(camera_.t.cast()); + + Vec3 projected = R * x + t; + projected /= projected(2); + + residuals[0] = projected(0) - T(marker_.x); + residuals[1] = projected(1) - T(marker_.y); + + return true; } - const vector &markers; - const EuclideanReconstruction &reconstruction; + + const Marker &marker_; + const EuclideanCamera &camera_; }; } // namespace @@ -95,13 +99,35 @@ bool EuclideanIntersect(const vector &markers, Xp /= Xp(3); Vec3 X = Xp.head<3>(); - typedef LevenbergMarquardt Solver; + ceres::Problem problem; - EuclideanIntersectCostFunction triangulate_cost(markers, *reconstruction); - Solver::SolverParameters params; - Solver solver(triangulate_cost); + for (int i = 0; i < markers.size(); ++i) { + const Marker &marker = markers[i]; + const EuclideanCamera &camera = + *reconstruction->CameraForImage(marker.image); + + problem.AddResidualBlock( + new ceres::AutoDiffCostFunction< + EuclideanIntersectCostFunctor, + 2, /* num_residuals */ + 3>(new EuclideanIntersectCostFunctor(marker, camera)), + NULL, + &X(0)); + } - Solver::Results results = solver.minimize(params, &X); + // Configure the solve. + ceres::Solver::Options solver_options; + solver_options.linear_solver_type = ceres::DENSE_NORMAL_CHOLESKY; + solver_options.max_num_iterations = 50; + solver_options.update_state_every_iteration = true; + solver_options.parameter_tolerance = 1e-16; + solver_options.function_tolerance = 1e-16; + + // Run the solve. + ceres::Solver::Summary summary; + ceres::Solve(solver_options, &problem, &summary); + + VLOG(1) << "Summary:\n" << summary.FullReport(); // Try projecting the point; make sure it's in front of everyone. for (int i = 0; i < cameras.size(); ++i) { -- cgit v1.2.3 From 0ec75be1c6c166d97dfb713169e381977df1da21 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 26 Feb 2013 11:46:38 +0000 Subject: Camera tracking: support refining radial K1, K2 only This commits adds extra refirenment entry in the menu which is "K1, K2" and which will apparently refine only this distortion coefficients. This would be useful in cases when you know for sure focal length (which could be obtained from lens, EXIF and so) but not sure about how good you manual calibration is. Be careful tho, there're no internal constraints on this coefficients so distortion model could just screw up into insane values. --- extern/libmv/libmv-capi.cpp | 4 +++- extern/libmv/libmv/simple_pipeline/bundle.cc | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'extern') diff --git a/extern/libmv/libmv-capi.cpp b/extern/libmv/libmv-capi.cpp index 945bc0c879e..4d6b35b91f8 100644 --- a/extern/libmv/libmv-capi.cpp +++ b/extern/libmv/libmv-capi.cpp @@ -437,7 +437,9 @@ int libmv_refineParametersAreValid(int parameters) { LIBMV_REFINE_RADIAL_DISTORTION_K1 | LIBMV_REFINE_RADIAL_DISTORTION_K2)) || (parameters == (LIBMV_REFINE_FOCAL_LENGTH | - LIBMV_REFINE_RADIAL_DISTORTION_K1)); + LIBMV_REFINE_RADIAL_DISTORTION_K1)) || + (parameters == (LIBMV_REFINE_RADIAL_DISTORTION_K1 | + LIBMV_REFINE_RADIAL_DISTORTION_K2)); } static void libmv_solveRefineIntrinsics(libmv::Tracks *tracks, libmv::CameraIntrinsics *intrinsics, diff --git a/extern/libmv/libmv/simple_pipeline/bundle.cc b/extern/libmv/libmv/simple_pipeline/bundle.cc index 0dd930a5ceb..7502ca389c4 100644 --- a/extern/libmv/libmv/simple_pipeline/bundle.cc +++ b/extern/libmv/libmv/simple_pipeline/bundle.cc @@ -208,6 +208,9 @@ void BundleIntrinsicsLogMessage(int bundle_intrinsics) { } else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH | BUNDLE_RADIAL_K1)) { LG << "Bundling f, k1."; + } else if (bundle_intrinsics == (BUNDLE_RADIAL_K1 | + BUNDLE_RADIAL_K2)) { + LG << "Bundling k1, k2."; } else { LOG(FATAL) << "Unsupported bundle combination."; } -- cgit v1.2.3 From 1d20f2496ab489c98224375ba63f4a726e931edb Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 26 Feb 2013 17:52:10 +0000 Subject: Use threaded cost function and jacobian computation Also made it theraded linear solver, seems it makes sense for iterative schur with inner iterations enabled. Use OpenMO's max therads called from bundler code to detect how many threads to use. Could be changed in a way that number of threads is passing in options from blender side in the future. Also removed redundant V3D definition from compiler's flags. --- extern/libmv/CMakeLists.txt | 1 - extern/libmv/bundle.sh | 2 -- extern/libmv/libmv/simple_pipeline/bundle.cc | 9 +++++++++ extern/libmv/third_party/ceres/CMakeLists.txt | 7 +++++++ extern/libmv/third_party/ceres/SConscript | 4 ++++ extern/libmv/third_party/ceres/bundle.sh | 11 +++++++++++ 6 files changed, 31 insertions(+), 3 deletions(-) (limited to 'extern') diff --git a/extern/libmv/CMakeLists.txt b/extern/libmv/CMakeLists.txt index 200e20de91b..1c289cd2778 100644 --- a/extern/libmv/CMakeLists.txt +++ b/extern/libmv/CMakeLists.txt @@ -216,7 +216,6 @@ else() endif() add_definitions( - -DV3DLIB_ENABLE_SUITESPARSE -DGOOGLE_GLOG_DLL_DECL= ) diff --git a/extern/libmv/bundle.sh b/extern/libmv/bundle.sh index 6b26bd95157..21d0308268a 100755 --- a/extern/libmv/bundle.sh +++ b/extern/libmv/bundle.sh @@ -195,7 +195,6 @@ ${third_glog_headers} endif() add_definitions( - -DV3DLIB_ENABLE_SUITESPARSE -DGOOGLE_GLOG_DLL_DECL= ) @@ -218,7 +217,6 @@ Import('env') defs = [] -defs.append('V3DLIB_ENABLE_SUITESPARSE') defs.append('GOOGLE_GLOG_DLL_DECL=') src = env.Glob("*.cpp") diff --git a/extern/libmv/libmv/simple_pipeline/bundle.cc b/extern/libmv/libmv/simple_pipeline/bundle.cc index 7502ca389c4..c29eb3d5df6 100644 --- a/extern/libmv/libmv/simple_pipeline/bundle.cc +++ b/extern/libmv/libmv/simple_pipeline/bundle.cc @@ -33,6 +33,10 @@ #include "libmv/simple_pipeline/reconstruction.h" #include "libmv/simple_pipeline/tracks.h" +#ifdef _OPENMP +# include +#endif + namespace libmv { // The intrinsics need to get combined into a single parameter block; use these @@ -332,6 +336,11 @@ void EuclideanBundleCommonIntrinsics(const Tracks &tracks, options.use_inner_iterations = true; options.max_num_iterations = 100; +#ifdef _OPENMP + options.num_threads = omp_get_max_threads(); + options.num_linear_solver_threads = omp_get_max_threads(); +#endif + ceres::Solver::Summary summary; ceres::Solve(options, &problem, &summary); diff --git a/extern/libmv/third_party/ceres/CMakeLists.txt b/extern/libmv/third_party/ceres/CMakeLists.txt index 5e58c2964ce..b71fe1d5cdb 100644 --- a/extern/libmv/third_party/ceres/CMakeLists.txt +++ b/extern/libmv/third_party/ceres/CMakeLists.txt @@ -261,8 +261,15 @@ add_definitions( -DCERES_NO_CXSPARSE -DCERES_NO_PROTOCOL_BUFFERS -DCERES_RESTRICT_SCHUR_SPECIALIZATION + -DCERES_HAVE_RWLOCK ) +if(WITH_OPENMP) + add_definitions( + -DCERES_USE_OPENMP + ) +endif() + if(MSVC10) add_definitions( -D"CERES_HASH_NAMESPACE_START=namespace std {" diff --git a/extern/libmv/third_party/ceres/SConscript b/extern/libmv/third_party/ceres/SConscript index 6d0d2cd5c40..6e490cfd5cf 100644 --- a/extern/libmv/third_party/ceres/SConscript +++ b/extern/libmv/third_party/ceres/SConscript @@ -23,6 +23,10 @@ defs.append('CERES_NO_SUITESPARSE') defs.append('CERES_NO_CXSPARSE') defs.append('CERES_NO_PROTOCOL_BUFFERS') defs.append('CERES_RESTRICT_SCHUR_SPECIALIZATION') +defs.append('CERES_HAVE_RWLOCK') + +if env['WITH_BF_OPENMP']: + defs.append('CERES_USE_OPENMP') if 'Mac OS X 10.5' in env['MACOSX_SDK_CHECK']: defs.append('CERES_NO_TR1') diff --git a/extern/libmv/third_party/ceres/bundle.sh b/extern/libmv/third_party/ceres/bundle.sh index b2c8330ec3e..65af263f7c4 100755 --- a/extern/libmv/third_party/ceres/bundle.sh +++ b/extern/libmv/third_party/ceres/bundle.sh @@ -162,8 +162,15 @@ add_definitions( -DCERES_NO_CXSPARSE -DCERES_NO_PROTOCOL_BUFFERS -DCERES_RESTRICT_SCHUR_SPECIALIZATION + -DCERES_HAVE_RWLOCK ) +if(WITH_OPENMP) + add_definitions( + -DCERES_USE_OPENMP + ) +endif() + if(MSVC10) add_definitions( -D"CERES_HASH_NAMESPACE_START=namespace std {" @@ -213,6 +220,10 @@ defs.append('CERES_NO_SUITESPARSE') defs.append('CERES_NO_CXSPARSE') defs.append('CERES_NO_PROTOCOL_BUFFERS') defs.append('CERES_RESTRICT_SCHUR_SPECIALIZATION') +defs.append('CERES_HAVE_RWLOCK') + +if env['WITH_BF_OPENMP']: + defs.append('CERES_USE_OPENMP') if 'Mac OS X 10.5' in env['MACOSX_SDK_CHECK']: defs.append('CERES_NO_TR1') -- cgit v1.2.3 From 9bfe99281cc5eb7e4308ccf086995c67ee90123a Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 28 Feb 2013 14:24:17 +0000 Subject: Move radial distortion code to own templated function This shall not lead to any functional changes, just avoids radial distortion code duplicated in camera intrinsics and bundling code. For fancier bundle adjustment supprting different distortion models this is not actually enough and would need to make some bigger changes, but this changes makes code a bit easier to maintain already. --- extern/libmv/libmv/simple_pipeline/bundle.cc | 21 +++++++-------- .../libmv/simple_pipeline/camera_intrinsics.cc | 24 +++++++---------- .../libmv/simple_pipeline/camera_intrinsics.h | 31 ++++++++++++++++++++++ 3 files changed, 51 insertions(+), 25 deletions(-) (limited to 'extern') diff --git a/extern/libmv/libmv/simple_pipeline/bundle.cc b/extern/libmv/libmv/simple_pipeline/bundle.cc index c29eb3d5df6..34117cbbbd7 100644 --- a/extern/libmv/libmv/simple_pipeline/bundle.cc +++ b/extern/libmv/libmv/simple_pipeline/bundle.cc @@ -94,17 +94,16 @@ struct OpenCVReprojectionError { // Apply distortion to the normalized points to get (xd, yd). // TODO(keir): Do early bailouts for zero distortion; these are expensive // jet operations. - T r2 = xn*xn + yn*yn; - T r4 = r2 * r2; - T r6 = r4 * r2; - T r_coeff = T(1) + k1*r2 + k2*r4 + k3*r6; - T xd = xn * r_coeff + T(2)*p1*xn*yn + p2*(r2 + T(2)*xn*xn); - T yd = yn * r_coeff + T(2)*p2*xn*yn + p1*(r2 + T(2)*yn*yn); - - // Apply focal length and principal point to get the final - // image coordinates. - predicted_x = focal_length * xd + principal_point_x; - predicted_y = focal_length * yd + principal_point_y; + + ApplyRadialDistortionCameraIntrinsics(focal_length, + focal_length, + principal_point_x, + principal_point_y, + k1, k2, k3, + p1, p2, + xn, yn, + &predicted_x, + &predicted_y); } else { predicted_x = xn; predicted_y = yn; diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc index 6319846a079..658f65c1367 100644 --- a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc +++ b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc @@ -124,20 +124,16 @@ void CameraIntrinsics::ApplyIntrinsics(double normalized_x, double normalized_y, double *image_x, double *image_y) const { - double x = normalized_x; - double y = normalized_y; - - // Apply distortion to the normalized points to get (xd, yd). - double r2 = x*x + y*y; - double r4 = r2 * r2; - double r6 = r4 * r2; - double r_coeff = (1 + k1_*r2 + k2_*r4 + k3_*r6); - double xd = x * r_coeff + 2*p1_*x*y + p2_*(r2 + 2*x*x); - double yd = y * r_coeff + 2*p2_*x*y + p1_*(r2 + 2*y*y); - - // Apply focal length and principal point to get the final image coordinates. - *image_x = focal_length_x() * xd + principal_point_x(); - *image_y = focal_length_y() * yd + principal_point_y(); + ApplyRadialDistortionCameraIntrinsics(focal_length_x(), + focal_length_y(), + principal_point_x(), + principal_point_y(), + k1(), k2(), k3(), + p1(), p2(), + normalized_x, + normalized_y, + image_x, + image_y); } struct InvertIntrinsicsCostFunction { diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h index e0556674ad5..b51b28a4bfb 100644 --- a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h +++ b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h @@ -159,6 +159,37 @@ class CameraIntrinsics { std::ostream& operator <<(std::ostream &os, const CameraIntrinsics &intrinsics); +// Apply camera intrinsics to the normalized point to get image coordinates. +// This applies the radial lens distortion to a point which is in normalized +// camera coordinates (i.e. the principal point is at (0, 0)) to get image +// coordinates in pixels. Templated for use with autodifferentiation. +template +inline void ApplyRadialDistortionCameraIntrinsics(T focal_length_x, + T focal_length_y, + T principal_point_x, + T principal_point_y, + T k1, T k2, T k3, + T p1, T p2, + T normalized_x, + T normalized_y, + T *image_x, + T *image_y) { + T x = normalized_x; + T y = normalized_y; + + // Apply distortion to the normalized points to get (xd, yd). + T r2 = x*x + y*y; + T r4 = r2 * r2; + T r6 = r4 * r2; + T r_coeff = (T(1) + k1*r2 + k2*r4 + k3*r6); + T xd = x * r_coeff + T(2)*p1*x*y + p2*(r2 + T(2)*x*x); + T yd = y * r_coeff + T(2)*p2*x*y + p1*(r2 + T(2)*y*y); + + // Apply focal length and principal point to get the final image coordinates. + *image_x = focal_length_x * xd + principal_point_x; + *image_y = focal_length_y * yd + principal_point_y; +} + } // namespace libmv #endif // LIBMV_SIMPLE_PIPELINE_CAMERA_INTRINSICS_H_ -- cgit v1.2.3 From 2a5ed5293dd430eefccd0a2e77c91729aff5b851 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 28 Feb 2013 14:24:25 +0000 Subject: Increase verbosity level for reprojected markers info This information is useful, but in cases when you, say, working on a bundler it's annoying to scroll all the information up. Now behavior would be: - running `./blender --debug-libmv` will print all the debug messages - running `./blender --debug-libmv --verbose 0` will print only debug messages from solvers, recosntruction and so, but will bypass final reprojection bunch of messages - running `./blender --debug-lib,v --verbose 1` will include final reprojection messages. --- extern/libmv/libmv/simple_pipeline/pipeline.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'extern') diff --git a/extern/libmv/libmv/simple_pipeline/pipeline.cc b/extern/libmv/libmv/simple_pipeline/pipeline.cc index efceda5c455..463738e42bb 100644 --- a/extern/libmv/libmv/simple_pipeline/pipeline.cc +++ b/extern/libmv/libmv/simple_pipeline/pipeline.cc @@ -300,7 +300,7 @@ double InternalReprojectionError(const Tracks &image_tracks, ex, ey, sqrt(ex*ex + ey*ey)); - LG << line; + VLOG(1) << line; total_error += sqrt(ex*ex + ey*ey); } -- cgit v1.2.3 From 52f34f017dca0bfe12976c997c2396de0dce2a71 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 28 Feb 2013 14:24:42 +0000 Subject: Modal (aka tripod) solver rework Several major things are done in this commit: - First of all, logic of modal solver was changed. We do not rely on only minimizer to take care of guessing rotation for frame, but we're using analytical rotation computation for point clouds to obtain initial rotation. Then this rotation is being refined using Ceres minimizer and now instead of minimizing average distance between points of point of two clouds, minimization of reprojection error of point cloud onto frame happens. This gives quite a bit of precision improvement. - Second bigger improvement here is using bundle adjustment for a result of first step when we're only estimating rotation between neighbor images and reprojecting markers. This averages error across the image sequence avoiding error accumulation. Also, this will tweak bundles themselves a bit for better match. - And last bigger improvement here is support of camera intrinsics refirenment. This allowed to significantly improve solution for real-life footage and results after such refining are much more usable than it were before. Thanks to Keir for the help and code review. --- extern/libmv/CMakeLists.txt | 1 + extern/libmv/files.txt | 20 +-- extern/libmv/libmv-capi.cpp | 27 ++- extern/libmv/libmv-capi.h | 1 + extern/libmv/libmv/multiview/panography.h | 181 +++++++++++++++++++++ extern/libmv/libmv/simple_pipeline/bundle.cc | 9 +- extern/libmv/libmv/simple_pipeline/bundle.h | 12 +- extern/libmv/libmv/simple_pipeline/modal_solver.cc | 179 ++++++++++++++++---- 8 files changed, 373 insertions(+), 57 deletions(-) create mode 100644 extern/libmv/libmv/multiview/panography.h (limited to 'extern') diff --git a/extern/libmv/CMakeLists.txt b/extern/libmv/CMakeLists.txt index 1c289cd2778..241e8bf2cd1 100644 --- a/extern/libmv/CMakeLists.txt +++ b/extern/libmv/CMakeLists.txt @@ -99,6 +99,7 @@ set(SRC libmv/multiview/homography.h libmv/multiview/homography_parameterization.h libmv/multiview/nviewtriangulation.h + libmv/multiview/panography.h libmv/multiview/projection.h libmv/multiview/resection.h libmv/multiview/triangulation.h diff --git a/extern/libmv/files.txt b/extern/libmv/files.txt index 22c5226adbe..8eead23ea08 100644 --- a/extern/libmv/files.txt +++ b/extern/libmv/files.txt @@ -21,6 +21,7 @@ libmv/multiview/homography.cc libmv/multiview/homography.h libmv/multiview/homography_parameterization.h libmv/multiview/nviewtriangulation.h +libmv/multiview/panography.h libmv/multiview/projection.cc libmv/multiview/projection.h libmv/multiview/resection.h @@ -142,25 +143,6 @@ third_party/glog/src/windows/glog/vlog_is_on.h third_party/glog/src/windows/port.cc third_party/glog/src/windows/port.h third_party/glog/src/windows/preprocess.sh -third_party/ldl/CMakeLists.txt -third_party/ldl/Doc/ChangeLog -third_party/ldl/Doc/lesser.txt -third_party/ldl/Include/ldl.h -third_party/ldl/README.libmv -third_party/ldl/README.txt -third_party/ldl/Source/ldl.c third_party/msinttypes/inttypes.h third_party/msinttypes/README.libmv third_party/msinttypes/stdint.h -third_party/ssba/COPYING.TXT -third_party/ssba/Geometry/v3d_cameramatrix.h -third_party/ssba/Geometry/v3d_distortion.h -third_party/ssba/Geometry/v3d_metricbundle.cpp -third_party/ssba/Geometry/v3d_metricbundle.h -third_party/ssba/Math/v3d_linear.h -third_party/ssba/Math/v3d_linear_utils.h -third_party/ssba/Math/v3d_mathutilities.h -third_party/ssba/Math/v3d_optimization.cpp -third_party/ssba/Math/v3d_optimization.h -third_party/ssba/README.libmv -third_party/ssba/README.TXT diff --git a/extern/libmv/libmv-capi.cpp b/extern/libmv/libmv-capi.cpp index 4d6b35b91f8..74224eb5368 100644 --- a/extern/libmv/libmv-capi.cpp +++ b/extern/libmv/libmv-capi.cpp @@ -444,7 +444,8 @@ int libmv_refineParametersAreValid(int parameters) { static void libmv_solveRefineIntrinsics(libmv::Tracks *tracks, libmv::CameraIntrinsics *intrinsics, libmv::EuclideanReconstruction *reconstruction, int refine_intrinsics, - reconstruct_progress_update_cb progress_update_callback, void *callback_customdata) + reconstruct_progress_update_cb progress_update_callback, void *callback_customdata, + int bundle_constraints = libmv::BUNDLE_NO_CONSTRAINTS) { /* only a few combinations are supported but trust the caller */ int libmv_refine_flags = 0; @@ -465,7 +466,7 @@ static void libmv_solveRefineIntrinsics(libmv::Tracks *tracks, libmv::CameraIntr progress_update_callback(callback_customdata, 1.0, "Refining solution"); libmv::EuclideanBundleCommonIntrinsics(*(libmv::Tracks *)tracks, libmv_refine_flags, - reconstruction, intrinsics); + reconstruction, intrinsics, bundle_constraints); } static void cameraIntrinsicsFromOptions(libmv::CameraIntrinsics *camera_intrinsics, @@ -568,6 +569,7 @@ libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *libmv_tracks, struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *libmv_tracks, libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, + libmv_reconstructionOptions *libmv_reconstruction_options, reconstruct_progress_update_cb progress_update_callback, void *callback_customdata) { @@ -582,13 +584,28 @@ struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *libmv_tracks, cameraIntrinsicsFromOptions(camera_intrinsics, libmv_camera_intrinsics_options); - /* Invert the camera intrinsics */ + /* Invert the camera intrinsics. */ libmv::Tracks normalized_tracks = getNormalizedTracks(tracks, camera_intrinsics); - /* actual reconstruction */ + /* Actual reconstruction. */ libmv::ModalSolver(normalized_tracks, reconstruction, &update_callback); - /* finish reconstruction */ + libmv::CameraIntrinsics empty_intrinsics; + libmv::EuclideanBundleCommonIntrinsics(normalized_tracks, + libmv::BUNDLE_NO_INTRINSICS, + reconstruction, + &empty_intrinsics, + libmv::BUNDLE_NO_TRANSLATION); + + /* Refinement. */ + if (libmv_reconstruction_options->refine_intrinsics) { + libmv_solveRefineIntrinsics((libmv::Tracks *)tracks, camera_intrinsics, reconstruction, + libmv_reconstruction_options->refine_intrinsics, + progress_update_callback, callback_customdata, + libmv::BUNDLE_NO_TRANSLATION); + } + + /* Finish reconstruction. */ finishReconstruction(tracks, camera_intrinsics, libmv_reconstruction, progress_update_callback, callback_customdata); diff --git a/extern/libmv/libmv-capi.h b/extern/libmv/libmv-capi.h index 588df8de440..af0d656146b 100644 --- a/extern/libmv/libmv-capi.h +++ b/extern/libmv/libmv-capi.h @@ -110,6 +110,7 @@ struct libmv_Reconstruction *libmv_solveReconstruction(struct libmv_Tracks *libm void *callback_customdata); struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *libmv_tracks, libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, + libmv_reconstructionOptions *libmv_reconstruction_options, reconstruct_progress_update_cb progress_update_callback, void *callback_customdata); int libmv_reporojectionPointForTrack(struct libmv_Reconstruction *libmv_reconstruction, int track, double pos[3]); diff --git a/extern/libmv/libmv/multiview/panography.h b/extern/libmv/libmv/multiview/panography.h new file mode 100644 index 00000000000..6f01beb0ffd --- /dev/null +++ b/extern/libmv/libmv/multiview/panography.h @@ -0,0 +1,181 @@ +// Copyright (c) 2009 libmv authors. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// + +#ifndef LIBMV_MULTIVIEW_PANOGRAPHY_H +#define LIBMV_MULTIVIEW_PANOGRAPHY_H + +#include "libmv/numeric/numeric.h" +#include "libmv/numeric/poly.h" +#include "libmv/base/vector.h" + +namespace libmv { + +static bool Build_Minimal2Point_PolynomialFactor( + const Mat & x1, const Mat & x2, + double * P) //P must be a double[4] +{ + assert(2 == x1.rows()); + assert(2 == x1.cols()); + assert(x1.rows() == x2.rows()); + assert(x1.cols() == x2.cols()); + + // Setup the variable of the input problem: + Vec xx1 = (x1.col(0)).transpose(); + Vec yx1 = (x1.col(1)).transpose(); + + double a12 = xx1.dot(yx1); + Vec xx2 = (x2.col(0)).transpose(); + Vec yx2 = (x2.col(1)).transpose(); + double b12 = xx2.dot(yx2); + + double a1 = xx1.squaredNorm(); + double a2 = yx1.squaredNorm(); + + double b1 = xx2.squaredNorm(); + double b2 = yx2.squaredNorm(); + + // Build the 3rd degre polynomial in F^2. + // + // f^6 * p + f^4 * q + f^2* r + s = 0; + // + // Coefficients in ascending powers of alpha, i.e. P[N]*x^N. + // Run panography_coeffs.py to get the below coefficients. + P[0] = b1*b2*a12*a12-a1*a2*b12*b12; + P[1] = -2*a1*a2*b12+2*a12*b1*b2+b1*a12*a12+b2*a12*a12-a1*b12*b12-a2*b12*b12; + P[2] = b1*b2-a1*a2-2*a1*b12-2*a2*b12+2*a12*b1+2*a12*b2+a12*a12-b12*b12; + P[3] = b1+b2-2*b12-a1-a2+2*a12; + + // If P[3] equal to 0 we get ill conditionned data + return (P[3] != 0.0); +} + +// This implements a minimal solution (2 points) for panoramic stitching: +// +// http://www.cs.ubc.ca/~mbrown/minimal/minimal.html +// +// [1] M. Brown and R. Hartley and D. Nister. Minimal Solutions for Panoramic +// Stitching. CVPR07. +// +// The 2-point algorithm solves for the rotation of the camera with a single +// focal length (4 degrees of freedom). +// +// Compute from 1 to 3 possible focal lenght for 2 point correspondences. +// Suppose that the cameras share the same optical center and focal lengths: +// +// Image 1 => H*x = x' => Image 2 +// x (u1j) x' (u2j) +// a (u11) a' (u21) +// b (u12) b' (u22) +// +// The return values are 1 to 3 possible values for the focal lengths such +// that: +// +// [f 0 0] +// K = [0 f 0] +// [0 0 1] +// +static void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2, + vector *fs) { + + // Build Polynomial factor to get squared focal value. + double P[4]; + Build_Minimal2Point_PolynomialFactor(x1, x2, &P[0]); + + // Solve it by using F = f^2 and a Cubic polynomial solver + // + // F^3 * p + F^2 * q + F^1 * r + s = 0 + // + double roots[3]; + int num_roots = SolveCubicPolynomial(P, roots); + for (int i = 0; i < num_roots; ++i) { + if (roots[i] > 0.0) { + fs->push_back(sqrt(roots[i])); + } + } +} + +// Compute the 3x3 rotation matrix that fits two 3D point clouds in the least +// square sense. The method is from: +// +// K. Arun,T. Huand and D. Blostein. Least-squares fitting of 2 3-D point +// sets. IEEE Transactions on Pattern Analysis and Machine Intelligence, +// 9:698-700, 1987. +// +// Given the calibration matrices K1, K2 solve for the rotation from +// corresponding image rays. +// +// R = min || X2 - R * x1 ||. +// +// In case of panography, which is for a camera that shares the same camera +// center, +// +// H = K2 * R * K1.inverse(); +// +// For the full explanation, see Section 8, Solving for Rotation from [1]. +// +// Parameters: +// +// x1 : Point cloud A (3D coords) +// x2 : Point cloud B (3D coords) +// +// [f 0 0] +// K1 = [0 f 0] +// [0 0 1] +// +// K2 (the same form as K1, but may have different f) +// +// Returns: A rotation matrix that minimizes +// +// R = arg min || X2 - R * x1 || +// +static void GetR_FixedCameraCenter(const Mat &x1, const Mat &x2, + const double focal, + Mat3 *R) { + assert(3 == x1.rows()); + assert(2 <= x1.cols()); + assert(x1.rows() == x2.rows()); + assert(x1.cols() == x2.cols()); + + // Build simplified K matrix + Mat3 K( Mat3::Identity() * 1.0/focal ); + K(2,2)= 1.0; + + // Build the correlation matrix; equation (22) in [1]. + Mat3 C = Mat3::Zero(); + for(int i = 0; i < x1.cols(); ++i) { + Mat r1i = (K * x1.col(i)).normalized(); + Mat r2i = (K * x2.col(i)).normalized(); + C += r2i * r1i.transpose(); + } + + // Solve for rotation. Equations (24) and (25) in [1]. + Eigen::JacobiSVD svd(C, Eigen::ComputeThinU | Eigen::ComputeThinV); + Mat3 scale = Mat3::Identity(); + scale(2,2) = ((svd.matrixU() * svd.matrixV().transpose()).determinant() > 0.0) + ? 1.0 + : -1.0; + + (*R) = svd.matrixU() * scale * svd.matrixV().transpose(); +} + +} // namespace libmv + +#endif // LIBMV_MULTIVIEW_PANOGRAPHY_H diff --git a/extern/libmv/libmv/simple_pipeline/bundle.cc b/extern/libmv/libmv/simple_pipeline/bundle.cc index 34117cbbbd7..3e36a78c9df 100644 --- a/extern/libmv/libmv/simple_pipeline/bundle.cc +++ b/extern/libmv/libmv/simple_pipeline/bundle.cc @@ -233,7 +233,8 @@ void EuclideanBundle(const Tracks &tracks, void EuclideanBundleCommonIntrinsics(const Tracks &tracks, int bundle_intrinsics, EuclideanReconstruction *reconstruction, - CameraIntrinsics *intrinsics) { + CameraIntrinsics *intrinsics, + int bundle_constraints) { LG << "Original intrinsics: " << *intrinsics; vector markers = tracks.AllMarkers(); @@ -270,7 +271,7 @@ void EuclideanBundleCommonIntrinsics(const Tracks &tracks, } problem.AddResidualBlock(new ceres::AutoDiffCostFunction< - OpenCVReprojectionError, 2, 8, 9 /* 3 */, 3, 3>( + OpenCVReprojectionError, 2, 8, 9, 3, 3>( new OpenCVReprojectionError( marker.x, marker.y)), @@ -284,6 +285,10 @@ void EuclideanBundleCommonIntrinsics(const Tracks &tracks, problem.SetParameterization(&camera->R(0, 0), &rotation_parameterization); + if (bundle_constraints & BUNDLE_NO_TRANSLATION) { + problem.SetParameterBlockConstant(&camera->t(0)); + } + num_residuals++; } LG << "Number of residuals: " << num_residuals; diff --git a/extern/libmv/libmv/simple_pipeline/bundle.h b/extern/libmv/libmv/simple_pipeline/bundle.h index 55657cb2d92..573bcf4cc21 100644 --- a/extern/libmv/libmv/simple_pipeline/bundle.h +++ b/extern/libmv/libmv/simple_pipeline/bundle.h @@ -67,6 +67,11 @@ void EuclideanBundle(const Tracks &tracks, BUNDLE_FOCAL_LENGTH | BUNDLE_PRINCIPAL_POINT BUNDLE_FOCAL_LENGTH | BUNDLE_PRINCIPAL_POINT | BUNDLE_RADIAL BUNDLE_FOCAL_LENGTH | BUNDLE_PRINCIPAL_POINT | BUNDLE_RADIAL | BUNDLE_TANGENTIAL + BUNDLE_RADIAL + + Constraints denotes which blocks to keep constant during bundling. + For example it is useful to keep camera translations constant + when bundling tripod motions. \note This assumes an outlier-free set of markers. @@ -83,10 +88,15 @@ enum BundleIntrinsics { BUNDLE_TANGENTIAL_P2 = 32, BUNDLE_TANGENTIAL = 48, }; +enum BundleConstraints { + BUNDLE_NO_CONSTRAINTS = 0, + BUNDLE_NO_TRANSLATION = 1, +}; void EuclideanBundleCommonIntrinsics(const Tracks &tracks, int bundle_intrinsics, EuclideanReconstruction *reconstruction, - CameraIntrinsics *intrinsics); + CameraIntrinsics *intrinsics, + int bundle_constraints = BUNDLE_NO_CONSTRAINTS); /*! Refine camera poses and 3D coordinates using bundle adjustment. diff --git a/extern/libmv/libmv/simple_pipeline/modal_solver.cc b/extern/libmv/libmv/simple_pipeline/modal_solver.cc index bb49b30dbce..aa2fa9a8a9d 100644 --- a/extern/libmv/libmv/simple_pipeline/modal_solver.cc +++ b/extern/libmv/libmv/simple_pipeline/modal_solver.cc @@ -18,11 +18,14 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. +#include "libmv/simple_pipeline/modal_solver.h" + #include +#include "ceres/ceres.h" +#include "ceres/rotation.h" #include "libmv/logging/logging.h" -#include "libmv/simple_pipeline/modal_solver.h" -#include "libmv/simple_pipeline/rigid_registration.h" +#include "libmv/multiview/panography.h" #ifdef _MSC_VER # define snprintf _snprintf @@ -30,7 +33,8 @@ namespace libmv { -static void ProjectMarkerOnSphere(Marker &marker, Vec3 &X) { +namespace { +void ProjectMarkerOnSphere(Marker &marker, Vec3 &X) { X(0) = marker.x; X(1) = marker.y; X(2) = 1.0; @@ -38,18 +42,59 @@ static void ProjectMarkerOnSphere(Marker &marker, Vec3 &X) { X *= 5.0 / X.norm(); } -static void ModalSolverLogProress(ProgressUpdateCallback *update_callback, - double progress) +void ModalSolverLogProress(ProgressUpdateCallback *update_callback, + double progress) { if (update_callback) { char message[256]; - snprintf(message, sizeof(message), "Solving progress %d%%", (int)(progress * 100)); + snprintf(message, sizeof(message), "Solving progress %d%%", + (int)(progress * 100)); update_callback->invoke(progress, message); } } +struct ModalReprojectionError { + ModalReprojectionError(Vec2 marker, Vec3 bundle) + : marker(marker), bundle(bundle) { } + + template + bool operator()(const T* quaternion, // Rotation quaternion + T* residuals) const { + + T R[9]; + ceres::QuaternionToRotation(quaternion, R); + + // Convert bundle position from double to T. + T X[3]; + X[0] = T(bundle(0)); + X[1] = T(bundle(1)); + X[2] = T(bundle(2)); + + // Compute projective coordinates: x = RX. + T x[3]; + x[0] = R[0]*X[0] + R[3]*X[1] + R[6]*X[2]; + x[1] = R[1]*X[0] + R[4]*X[1] + R[7]*X[2]; + x[2] = R[2]*X[0] + R[5]*X[1] + R[8]*X[2]; + + // Compute normalized coordinates: x /= x[2]. + T xn = x[0] / x[2]; + T yn = x[1] / x[2]; + + // The error is the difference between reprojected + // and observed marker position. + residuals[0] = xn - T(marker(0)); + residuals[1] = yn - T(marker(1)); + + return true; + } + + Vec2 marker; + Vec3 bundle; +}; +} // namespace + void ModalSolver(Tracks &tracks, EuclideanReconstruction *reconstruction, ProgressUpdateCallback *update_callback) { @@ -59,58 +104,132 @@ void ModalSolver(Tracks &tracks, LG << "Max image: " << max_image; LG << "Max track: " << max_track; - Mat3 R = Mat3::Identity(); + // For minimization we're using quaternions. + Vec3 zero_rotation = Vec3::Zero(); + Vec4 quaternion; + ceres::AngleAxisToQuaternion(&zero_rotation(0), &quaternion(0)); for (int image = 0; image <= max_image; ++image) { vector all_markers = tracks.MarkersInImage(image); ModalSolverLogProress(update_callback, (float) image / max_image); - // Skip empty frames without doing anything + // Skip empty images without doing anything. if (all_markers.size() == 0) { - LG << "Skipping frame: " << image; + LG << "Skipping image: " << image; continue; } - vector points, reference_points; + // STEP 1: Estimate rotation analytically. + Mat3 current_R; + ceres::QuaternionToRotation(&quaternion(0), ¤t_R(0, 0)); + + // Construct point cloud for current and previous images, + // using markers appear at current image for which we know + // 3D positions. + Mat x1, x2; + for (int i = 0; i < all_markers.size(); ++i) { + Marker &marker = all_markers[i]; + EuclideanPoint *point = reconstruction->PointForTrack(marker.track); + if (point) { + Vec3 X; + ProjectMarkerOnSphere(marker, X); - // Cnstruct pairs of markers from current and previous image, - // to reproject them and find rigid transformation between - // previous and current image - for (int track = 0; track <= max_track; ++track) { - EuclideanPoint *point = reconstruction->PointForTrack(track); + int last_column = x1.cols(); + x1.conservativeResize(3, last_column + 1); + x2.conservativeResize(3, last_column + 1); - if (point) { - Marker marker = tracks.MarkerInImageForTrack(image, track); + x1.col(last_column) = current_R * point->X; + x2.col(last_column) = X; + } + } - if (marker.image == image) { - Vec3 X; + if (x1.cols() >= 2) { + Mat3 delta_R; - LG << "Use track " << track << " for rigid registration between image " << - image - 1 << " and " << image; + // Compute delta rotation matrix for two point clouds. + // Could be a bit confusing at first glance, but order + // of clouds is indeed so. + GetR_FixedCameraCenter(x2, x1, 1.0, &delta_R); - ProjectMarkerOnSphere(marker, X); + // Convert delta rotation form matrix to final image + // rotation stored in a quaternion + Vec3 delta_angle_axis; + ceres::RotationMatrixToAngleAxis(&delta_R(0, 0), &delta_angle_axis(0)); - points.push_back(point->X); - reference_points.push_back(X); - } + Vec3 current_angle_axis; + ceres::QuaternionToAngleAxis(&quaternion(0), ¤t_angle_axis(0)); + + Vec3 angle_axis = current_angle_axis + delta_angle_axis; + + ceres::AngleAxisToQuaternion(&angle_axis(0), &quaternion(0)); + + LG << "Analytically computed quaternion " + << quaternion.transpose(); + } + + // STEP 2: Refine rotation with Ceres. + ceres::Problem problem; + + ceres::LocalParameterization* quaternion_parameterization = + new ceres::QuaternionParameterization; + + int num_residuals = 0; + for (int i = 0; i < all_markers.size(); ++i) { + Marker &marker = all_markers[i]; + EuclideanPoint *point = reconstruction->PointForTrack(marker.track); + + if (point) { + problem.AddResidualBlock(new ceres::AutoDiffCostFunction< + ModalReprojectionError, + 2, /* num_residuals */ + 4>(new ModalReprojectionError(Vec2(marker.x, marker.y), + point->X)), + NULL, + &quaternion(0)); + num_residuals++; + + problem.SetParameterization(&quaternion(0), + quaternion_parameterization); } } - if (points.size()) { - // Find rigid delta transformation to current image - RigidRegistration(reference_points, points, R); + LG << "Number of residuals: " << num_residuals; + + if (num_residuals) { + // Configure the solve. + ceres::Solver::Options solver_options; + solver_options.linear_solver_type = ceres::DENSE_NORMAL_CHOLESKY; + solver_options.max_num_iterations = 50; + solver_options.update_state_every_iteration = true; + solver_options.gradient_tolerance = 1e-36; + solver_options.parameter_tolerance = 1e-36; + solver_options.function_tolerance = 1e-36; + + // Run the solve. + ceres::Solver::Summary summary; + ceres::Solve(solver_options, &problem, &summary); + + LG << "Summary:\n" << summary.FullReport(); + LG << "Refined quaternion " << quaternion.transpose(); } + // Convert quaternion to rotation matrix. + Mat3 R; + ceres::QuaternionToRotation(&quaternion(0), &R(0, 0)); reconstruction->InsertCamera(image, R, Vec3::Zero()); - // Review if there's new tracks for which position might be reconstructed + // STEP 3: reproject all new markers appeared at image + + // Check if there're new markers appeared on current image + // and reproject them on sphere to obtain 3D position/ for (int track = 0; track <= max_track; ++track) { if (!reconstruction->PointForTrack(track)) { Marker marker = tracks.MarkerInImageForTrack(image, track); if (marker.image == image) { - // New track appeared on this image, project it's position onto sphere + // New track appeared on this image, + // project it's position onto sphere. LG << "Projecting track " << track << " at image " << image; -- cgit v1.2.3 From 3e320a67e3fa1226c95bb37250649fb26f0d916e Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 28 Feb 2013 14:24:52 +0000 Subject: Remove unused rigid registration code There're some features planned which would require rigid registration, but this code would need to be re-done anyway to use new minimizer and solving some issues with ICP algorithm there. --- extern/libmv/CMakeLists.txt | 2 - extern/libmv/files.txt | 2 - extern/libmv/libmv-capi.cpp | 54 ------ .../libmv/simple_pipeline/rigid_registration.cc | 182 --------------------- .../libmv/simple_pipeline/rigid_registration.h | 68 -------- 5 files changed, 308 deletions(-) delete mode 100644 extern/libmv/libmv/simple_pipeline/rigid_registration.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/rigid_registration.h (limited to 'extern') diff --git a/extern/libmv/CMakeLists.txt b/extern/libmv/CMakeLists.txt index 241e8bf2cd1..a4910d94a37 100644 --- a/extern/libmv/CMakeLists.txt +++ b/extern/libmv/CMakeLists.txt @@ -59,7 +59,6 @@ set(SRC libmv/simple_pipeline/pipeline.cc libmv/simple_pipeline/reconstruction.cc libmv/simple_pipeline/resect.cc - libmv/simple_pipeline/rigid_registration.cc libmv/simple_pipeline/tracks.cc libmv/tracking/brute_region_tracker.cc libmv/tracking/esm_region_tracker.cc @@ -118,7 +117,6 @@ set(SRC libmv/simple_pipeline/pipeline.h libmv/simple_pipeline/reconstruction.h libmv/simple_pipeline/resect.h - libmv/simple_pipeline/rigid_registration.h libmv/simple_pipeline/tracks.h libmv/tracking/brute_region_tracker.h libmv/tracking/esm_region_tracker.h diff --git a/extern/libmv/files.txt b/extern/libmv/files.txt index 8eead23ea08..16afdb36371 100644 --- a/extern/libmv/files.txt +++ b/extern/libmv/files.txt @@ -54,8 +54,6 @@ libmv/simple_pipeline/reconstruction.cc libmv/simple_pipeline/reconstruction.h libmv/simple_pipeline/resect.cc libmv/simple_pipeline/resect.h -libmv/simple_pipeline/rigid_registration.cc -libmv/simple_pipeline/rigid_registration.h libmv/simple_pipeline/tracks.cc libmv/simple_pipeline/tracks.h libmv/tracking/brute_region_tracker.cc diff --git a/extern/libmv/libmv-capi.cpp b/extern/libmv/libmv-capi.cpp index 74224eb5368..c915205dd16 100644 --- a/extern/libmv/libmv-capi.cpp +++ b/extern/libmv/libmv-capi.cpp @@ -56,7 +56,6 @@ #include "libmv/simple_pipeline/detect.h" #include "libmv/simple_pipeline/pipeline.h" #include "libmv/simple_pipeline/camera_intrinsics.h" -#include "libmv/simple_pipeline/rigid_registration.h" #include "libmv/simple_pipeline/modal_solver.h" #include @@ -968,56 +967,3 @@ void libmv_InvertIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsi camera_intrinsics.InvertIntrinsics(x, y, x1, y1); } } - -/* ************ point clouds ************ */ - -static void libmvTransformToMat4(libmv::Mat3 &R, libmv::Vec3 &S, libmv::Vec3 &t, double M[4][4]) -{ - for (int j = 0; j < 3; ++j) - for (int k = 0; k < 3; ++k) - M[j][k] = R(k, j) * S(j); - - for (int i = 0; i < 3; ++i) { - M[3][0] = t(0); - M[3][1] = t(1); - M[3][2] = t(2); - - M[0][3] = M[1][3] = M[2][3] = 0; - } - - M[3][3] = 1.0; -} - -void libmv_rigidRegistration(float (*reference_points)[3], float (*points)[3], int total_points, - int use_scale, int use_translation, double M[4][4]) -{ - libmv::Mat3 R; - libmv::Vec3 S; - libmv::Vec3 t; - libmv::vector reference_points_vector, points_vector; - - for (int i = 0; i < total_points; i++) { - reference_points_vector.push_back(libmv::Vec3(reference_points[i][0], - reference_points[i][1], - reference_points[i][2])); - - points_vector.push_back(libmv::Vec3(points[i][0], - points[i][1], - points[i][2])); - } - - if (use_scale && use_translation) { - libmv::RigidRegistration(reference_points_vector, points_vector, R, S, t); - } - else if (use_translation) { - S = libmv::Vec3(1.0, 1.0, 1.0); - libmv::RigidRegistration(reference_points_vector, points_vector, R, t); - } - else { - S = libmv::Vec3(1.0, 1.0, 1.0); - t = libmv::Vec3::Zero(); - libmv::RigidRegistration(reference_points_vector, points_vector, R); - } - - libmvTransformToMat4(R, S, t, M); -} diff --git a/extern/libmv/libmv/simple_pipeline/rigid_registration.cc b/extern/libmv/libmv/simple_pipeline/rigid_registration.cc deleted file mode 100644 index f7cb1e66e7d..00000000000 --- a/extern/libmv/libmv/simple_pipeline/rigid_registration.cc +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) 2012 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/rigid_registration.h" -#include "libmv/numeric/levenberg_marquardt.h" - -namespace libmv { - -template -struct RigidRegistrationCostFunction { - public: - typedef Vec FMatrixType; - typedef RigidTransformation XMatrixType; - - RigidRegistrationCostFunction(const vector &reference_points, - const vector &points): - reference_points_(reference_points), - points_(points) {} - - Vec CalculateResiduals(const Mat3 &R, - const Vec3 &S, - const Vec3 &t) const { - Vec residuals(points_.size()); - residuals.setZero(); - - // Convert scale vector to matrix - Mat3 SMat = Mat3::Identity(); - SMat(0, 0) *= S(0); - SMat(1, 1) *= S(1); - SMat(2, 2) *= S(2); - - for (int i = 0; i < points_.size(); i++) { - Vec3 transformed_point = R * SMat * points_[i] + t; - - double norm = (transformed_point - reference_points_[i]).norm(); - - residuals(i) = norm * norm; - } - - return residuals; - } - - Vec operator()(const Vec9 &RSt) const { - Mat3 R = RotationFromEulerVector(RSt.head<3>()); - Vec3 S = RSt.segment<3>(3); - Vec3 t = RSt.tail<3>(); - - return CalculateResiduals(R, S, t); - } - - Vec operator()(const Vec3 &euler) const { - Mat3 R = RotationFromEulerVector(euler); - - return CalculateResiduals(R, Vec3(1.0, 1.0, 1.0), Vec3::Zero()); - } - - Vec operator()(const Vec6 &Rt) const { - Mat3 R = RotationFromEulerVector(Rt.head<3>()); - Vec3 t = Rt.tail<3>(); - - return CalculateResiduals(R, Vec3(1.0, 1.0, 1.0), t); - } - - private: - vector reference_points_; - vector points_; -}; - -static double RigidRegistrationError(const vector &reference_points, - const vector &points, - const Mat3 &R, - const Vec3 &S, - const Vec3 &t) { - double error = 0.0; - - Mat3 SMat = Mat3::Identity(); - SMat(0, 0) *= S(0); - SMat(1, 1) *= S(1); - SMat(2, 2) *= S(2); - - for (int i = 0; i < points.size(); i++) { - Vec3 new_point = R * SMat * points[i] + t; - - double norm = (new_point - reference_points[i]).norm(); - error += norm * norm; - } - error /= points.size(); - - return error; -} - -double RigidRegistration(const vector &reference_points, - const vector &points, - Mat3 &R, - Vec3 &S, - Vec3 &t) { - typedef LevenbergMarquardt > Solver; - - RigidRegistrationCostFunction rigidregistration_cost(reference_points, points); - Solver solver(rigidregistration_cost); - - Vec9 RSt = Vec9::Zero(); - - RSt(3) = RSt(4) = RSt(5) = 1.0; - - Solver::SolverParameters params; - /*Solver::Results results = */ solver.minimize(params, &RSt); - /* TODO(sergey): better error handling here */ - - LG << "Rigid registration completed, rotation is:" << RSt.head<3>().transpose() - << ", scale is " << RSt.segment<3>(3).transpose() - << ", translation is " << RSt.tail<3>().transpose(); - - // Decompose individual rotation and translation - R = RotationFromEulerVector(RSt.head<3>()); - S = RSt.segment<3>(3); - t = RSt.tail<3>(); - - return RigidRegistrationError(reference_points, points, R, S, t); -} - -double RigidRegistration(const vector &reference_points, - const vector &points, - Mat3 &R, - Vec3 &t) { - typedef LevenbergMarquardt > Solver; - - RigidRegistrationCostFunction rigidregistration_cost(reference_points, points); - Solver solver(rigidregistration_cost); - - Vec6 Rt = Vec6::Zero(); - Solver::SolverParameters params; - /*Solver::Results results = */solver.minimize(params, &Rt); - /* TODO(sergey): better error handling here */ - - LG << "Rigid registration completed, rotation is:" << Rt.head<3>().transpose() - << ", translation is " << Rt.tail<3>().transpose(); - - R = RotationFromEulerVector(Rt.head<3>()); - t = Rt.tail<3>(); - - return RigidRegistrationError(reference_points, points, R, Vec3(1.0, 1.0, 1.0), t); -} - -double RigidRegistration(const vector &reference_points, - const vector &points, - Mat3 &R) { - typedef LevenbergMarquardt > Solver; - - RigidRegistrationCostFunction rigidregistration_cost(reference_points, points); - Solver solver(rigidregistration_cost); - - Vec3 euler = Vec3::Zero(); - Solver::SolverParameters params; - /*Solver::Results results = */solver.minimize(params, &euler); - /* TODO(sergey): better error handling here */ - - LG << "Rigid registration completed, rotation is:" << euler.transpose(); - - R = RotationFromEulerVector(euler); - - return RigidRegistrationError(reference_points, points, R, Vec3(1.0, 1.0, 1.0), Vec3::Zero()); -} - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/rigid_registration.h b/extern/libmv/libmv/simple_pipeline/rigid_registration.h deleted file mode 100644 index 21ea57af507..00000000000 --- a/extern/libmv/libmv/simple_pipeline/rigid_registration.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2012 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_SIMPLE_PIPELINE_RIGID_REGISTRATION_H_ -#define LIBMV_SIMPLE_PIPELINE_RIGID_REGISTRATION_H_ - -#include "libmv/base/vector.h" -#include "libmv/numeric/numeric.h" - -namespace libmv { - -/*! - Searched for an affine transformation of rigid 3D object defined by it's - vertices positions from it's current state called points to it's desired - state called reference points. - - Returns rotation matrix, per-component scale vector and translation which - transforms points to the mot close state to reference_points. - - Return value is an average squared distance between reference state - and transformed one. - - Minimzation of distance between point pairs is used to register such a - rigid transformation and algorithm assumes that pairs of points are - defined by point's index in a vector, so points with the same index - belongs to the same pair. - */ -double RigidRegistration(const vector &reference_points, - const vector &points, - Mat3 &R, - Vec3 &S, - Vec3 &t); - -/*! - * Same as RigidRegistration but provides registration of rotation and translation only - */ -double RigidRegistration(const vector &reference_points, - const vector &points, - Mat3 &R, - Vec3 &t); - -/*! - * Same as RigidRegistration but provides registration of rotation only - */ -double RigidRegistration(const vector &reference_points, - const vector &points, - Mat3 &R); - -} // namespace libmv - -#endif // LIBMV_SIMPLE_PIPELINE_RIGID_REGISTRATION_H_ -- cgit v1.2.3 From d68e766c8c3adda4bf5576f43d69d12818ce3b1f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 28 Feb 2013 14:25:33 +0000 Subject: This lines are also not so much useful for now. --- extern/libmv/libmv-capi.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'extern') diff --git a/extern/libmv/libmv-capi.h b/extern/libmv/libmv-capi.h index af0d656146b..c90322c56c5 100644 --- a/extern/libmv/libmv-capi.h +++ b/extern/libmv/libmv-capi.h @@ -162,10 +162,6 @@ void libmv_applyCameraIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_int void libmv_InvertIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options, double x, double y, double *x1, double *y1); -/* point clouds */ -void libmv_rigidRegistration(float (*reference_points)[3], float (*points)[3], int total_points, - int use_scale, int use_translation, double M[4][4]); - #ifdef __cplusplus } #endif -- cgit v1.2.3 From aada0e4a29b8e5e1fcdf5d37bae0bfb17b4eb199 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 28 Feb 2013 14:25:40 +0000 Subject: Header cleanup in libmv c-api --- extern/libmv/libmv-capi.cpp | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'extern') diff --git a/extern/libmv/libmv-capi.cpp b/extern/libmv/libmv-capi.cpp index c915205dd16..a85c3268b16 100644 --- a/extern/libmv/libmv-capi.cpp +++ b/extern/libmv/libmv-capi.cpp @@ -34,19 +34,8 @@ #include "libmv-capi.h" -#include "third_party/gflags/gflags/gflags.h" -#include "glog/logging.h" #include "libmv/logging/logging.h" -#include "libmv/numeric/numeric.h" - -#include "libmv/tracking/esm_region_tracker.h" -#include "libmv/tracking/brute_region_tracker.h" -#include "libmv/tracking/hybrid_region_tracker.h" -#include "libmv/tracking/klt_region_tracker.h" -#include "libmv/tracking/trklt_region_tracker.h" -#include "libmv/tracking/lmicklt_region_tracker.h" -#include "libmv/tracking/pyramid_region_tracker.h" #include "libmv/tracking/track_region.h" #include "libmv/simple_pipeline/callbacks.h" -- cgit v1.2.3 From a2027237edc49d5b7926f5de6df855d163edcf8e Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 1 Mar 2013 08:20:13 +0000 Subject: Pass data to modal reprojection cost functor by reference Seems it solves alignment error reported by 32bit MSVC. --- extern/libmv/libmv/simple_pipeline/modal_solver.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'extern') diff --git a/extern/libmv/libmv/simple_pipeline/modal_solver.cc b/extern/libmv/libmv/simple_pipeline/modal_solver.cc index aa2fa9a8a9d..e14f1db272b 100644 --- a/extern/libmv/libmv/simple_pipeline/modal_solver.cc +++ b/extern/libmv/libmv/simple_pipeline/modal_solver.cc @@ -56,7 +56,7 @@ void ModalSolverLogProress(ProgressUpdateCallback *update_callback, } struct ModalReprojectionError { - ModalReprojectionError(Vec2 marker, Vec3 bundle) + ModalReprojectionError(Vec2 &marker, Vec3 &bundle) : marker(marker), bundle(bundle) { } template -- cgit v1.2.3 From 1a7ab1da099a7e3bd1de03d721f049909963f105 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 1 Mar 2013 08:56:04 +0000 Subject: Hrm, gcc became broken after recent commit. Hope now gcc and 32bit msvc would both work. --- extern/libmv/libmv/simple_pipeline/modal_solver.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'extern') diff --git a/extern/libmv/libmv/simple_pipeline/modal_solver.cc b/extern/libmv/libmv/simple_pipeline/modal_solver.cc index e14f1db272b..169c53bb601 100644 --- a/extern/libmv/libmv/simple_pipeline/modal_solver.cc +++ b/extern/libmv/libmv/simple_pipeline/modal_solver.cc @@ -56,8 +56,8 @@ void ModalSolverLogProress(ProgressUpdateCallback *update_callback, } struct ModalReprojectionError { - ModalReprojectionError(Vec2 &marker, Vec3 &bundle) - : marker(marker), bundle(bundle) { } + ModalReprojectionError(double observed_x, double observed_y, Vec3 &bundle) + : observed_x(observed_x), observed_y(observed_y), bundle(bundle) { } template bool operator()(const T* quaternion, // Rotation quaternion @@ -84,13 +84,14 @@ struct ModalReprojectionError { // The error is the difference between reprojected // and observed marker position. - residuals[0] = xn - T(marker(0)); - residuals[1] = yn - T(marker(1)); + residuals[0] = xn - T(observed_x); + residuals[1] = yn - T(observed_y); return true; } - Vec2 marker; + double observed_x; + double observed_y; Vec3 bundle; }; } // namespace @@ -183,7 +184,7 @@ void ModalSolver(Tracks &tracks, problem.AddResidualBlock(new ceres::AutoDiffCostFunction< ModalReprojectionError, 2, /* num_residuals */ - 4>(new ModalReprojectionError(Vec2(marker.x, marker.y), + 4>(new ModalReprojectionError(marker.x, marker.y, point->X)), NULL, &quaternion(0)); -- cgit v1.2.3 From 9da36d3ab1cbc34968350fe0440528016d8fa423 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 1 Mar 2013 11:52:38 +0000 Subject: Updates to libmv's bundle.sh to make sure libmv upstream is copying properly to our sources. --- extern/libmv/ChangeLog | 300 ++++++++++++++++--------------- extern/libmv/SConscript | 1 - extern/libmv/bundle.sh | 1 - extern/libmv/patches/series | 1 - extern/libmv/patches/v3d_verbosity.patch | 12 -- 5 files changed, 155 insertions(+), 160 deletions(-) delete mode 100644 extern/libmv/patches/v3d_verbosity.patch (limited to 'extern') diff --git a/extern/libmv/ChangeLog b/extern/libmv/ChangeLog index 222fc4eaa1f..a4f25f83a1c 100644 --- a/extern/libmv/ChangeLog +++ b/extern/libmv/ChangeLog @@ -1,3 +1,158 @@ +commit 473996468a4e67e7c860169181a4ff31ce9b8c80 +Author: Sergey Sharybin +Date: Fri Mar 1 17:44:54 2013 +0600 + + Fixed incorrect order of arguments passing + to EXPECT_EQ in keyframe selection tests. + +commit d38ebb74693fdf5b8f0fecf62a3d8c9c53b0b84a +Author: Sergey Sharybin +Date: Fri Mar 1 17:40:38 2013 +0600 + + Modal (aka tripod) solver rework + + Several major things are done in this commit: + + - First of all, logic of modal solver was changed. + We do not rely on only minimizer to take care of + guessing rotation for frame, but we're using + analytical rotation computation for point clouds + to obtain initial rotation. + + Then this rotation is being refined using Ceres + minimizer and now instead of minimizing average + distance between points of point of two clouds, + minimization of reprojection error of point + cloud onto frame happens. + + This gives quite a bit of precision improvement. + + - Second bigger improvement here is using bundle + adjustment for a result of first step when we're + only estimating rotation between neighbor images + and reprojecting markers. + + This averages error across the image sequence + avoiding error accumulation. Also, this will + tweak bundles themselves a bit for better match. + + - And last bigger improvement here is support of + camera intrinsics refirenment. + + This allowed to significantly improve solution + for real-life footage and results after such + refining are much more usable than it were before. + + Thanks to Keir for the help and code review! + +commit 5d6c2e7a27bdd1a1b23bf289d70a9b8f62514c9a +Author: Sergey Sharybin +Date: Fri Mar 1 17:37:35 2013 +0600 + + Increase verbosity level for reprojected markers info + + This information is useful, but in cases when you, say, + working on a bundler it's annoying to scroll all the + information up. + +commit ac252bb1250b3028b9c94736b644e7ab4e7b14b8 +Author: Sergey Sharybin +Date: Fri Mar 1 17:36:19 2013 +0600 + + Move radial distortion code to own templated function + + This shall not lead to any functional changes, just + avoids radial distortion code duplicated in camera + intrinsics and bundling code. + + For fancier bundle adjustment support of different + distortion models this is not actually enough and + would need to make some bigger changes, but this + changes makes code a bit easier to maintain already. + +commit c253b794612dd529e1d3a9bd7a7c41c32c9a9abb +Author: Sergey Sharybin +Date: Fri Mar 1 17:33:27 2013 +0600 + + Use threaded cost function, jacobian and linear solver + computation, so bundling is as fast as it could be with + current parameter block structure. + +commit 931fe37a10212b91b525d4f6eb753990a338b471 +Author: Sergey Sharybin +Date: Fri Mar 1 17:29:21 2013 +0600 + + Fixed comment for euclidean bundling, + which is now supports raidal bundling independently + from other intrinsics. + +commit 217d8e6edc3de1a853fb84275d2d2dd898e7529c +Author: Sergey Sharybin +Date: Tue Feb 26 18:19:01 2013 +0600 + + Allow K1,K2 refirement combination + + It is now possible to refine only radial distortion + with new Ceres based bundler and this new combination + is already used in Blender. + +commit d8850addc944d400f7a9c358396c437d9e4acc70 +Author: Sergey Sharybin +Date: Tue Feb 26 18:17:09 2013 +0600 + + Switch euclidean intersection code to use Ceres + + Would not expect any significant changes in solver + behavior, but it could be more accurate in some cases. + + Switching projective intersection to ceres is marked + as a TODO for now. + +commit 6990b7946ec96b3cb2dcfc8a1beaaba9538b0802 +Author: Keir Mierle +Date: Mon Feb 25 20:00:48 2013 +0000 + + Switch motion tracker bundle adjustment to Ceres. + + Patch originally written by me, then finished by Sergey. Big + thanks to Sergey for troopering through and fixing the many issues + with my original (not compilable) patch. + + The Ceres implementation uses 2 parameter blocks for each camera + (1 for rotation and 1 for translation), 1 parameter block for + common intrinsics (focal length etc) and 1 parameter block for + each track (e.g. bundle or 3D point). + + We turn on some fancy optimizer options to get better performance, + in particular: + + options.preconditioner_type = ceres::SCHUR_JACOBI; + options.linear_solver_type = ceres::ITERATIVE_SCHUR; + options.use_inner_iterations = true; + options.use_nonmonotonic_steps = true; + options.max_num_iterations = 100; + + Special thanks to Sameer Agarwal of Ceres fame for splitting out + the SCHUR_JACOBI preconditioner so that it didn't depend on + CHOLMOD. Previously we could not use that preconditioner in + Blender because CHOLMOD is too large of a dependency for Blender. + + BundleIntrinsicsLogMessage: + - Moved bunch of if(foo) LG << "bar" into this function, to make + EuclideanBundleCommonIntrinsics a little bit easier to follow. + + EuclideanBundle: + - Fix RMSE logging. + +commit 1696342954614b54133780d74d6ee0fbcbe224f0 +Author: Sergey Sharybin +Date: Tue Feb 26 18:10:33 2013 +0600 + + Upgrade ceres to latest upstream version + + This is needed because of some features of new Ceres + for further development. + commit 575336f794841ada90aacd783285014081b8318c Author: Sergey Sharybin Date: Mon Jan 7 15:58:40 2013 +0600 @@ -643,148 +798,3 @@ Date: Thu Apr 12 13:56:02 2012 +0600 It projects markers onto sphere and uses rigid registration of rotation to find rotation angles which makes bundles from previous and current frame be as closest as it's possible. - -commit fa3842e472e3b9c789e47bf6d8f592aa40a84f16 -Author: Sergey Sharybin -Date: Thu Apr 12 12:32:48 2012 +0600 - - implementation of some basic algorithms for point cloud orientation: - - - Implementation of rigid registration algorithm which searches transformation - form one point cloud to another assuming that points in this clouds are - already paired (points with the same index in different clouds belongs to - the same pair) which minimizes average distance between points in pairs. - - Algorithm uses Levenberg-Marquardt solver to find such transformation. - - Supports registration of rotation-scale-transform (which is probably most - common usage) and rotation only (which might be useful for basic modal - tripod solver). - - - Implementation of Iterative-Point-Clouds algorithm which searches - transformation from one arbitrary point cloud to another making - points as closest to each other as possible. - - This algorithm doesn't require points be initially paired, but for - good result clouds should have rough initial orientation. If they're - arbitrary oriented from the very beginning, algorithm might fail - producing good resold. - - Iteration is based on building pairs of closest to each other points - and registering rigid transformation between them which incrementally - constructs final result. - - TODO: building pairs might be speedup a lot using data structures like - AABB trees, K-D trees or so. - -commit 9618d9a1d48bb3c28da605d9027f57a74f462785 -Author: Sergey Sharybin -Date: Wed Apr 11 14:17:14 2012 +0600 - - Added configuration file for glog to compile smooth on Hurd platform. - - Patch by Pino Toscano , thanks! - -commit 63b2bd20237c8599fa73ce42556e4fb99b9f7cca -Author: Sergey Sharybin -Date: Thu Mar 22 17:03:34 2012 +0600 - - Trackers refactoring: - - Deduplicate pattern sampling used in esm and lmicklt trackers - and move SamplePattern to image/sample.h - - Move computation of Pearson product-moment correlation into - own function in new file image/correlation.h so all trackers - can use it to check final correlation. - - Remove SAD tracker. It's almost the same as brute tracker, - with only two differences: - 1. It does brute search of affine transformation which in some cases - helps to track rotating features - 2. It didn't use common tracker api which probably gave some speed - advantage, but lead to a real headache to use it together with - other trackers leading to duplicated code in 3d-party software. - -commit 9fe49c32e990f28c83f2bbb1d18057aed8879af7 -Author: Sergey Sharybin -Date: Mon Mar 12 09:36:15 2012 +0600 - - Code cleanup: convert line endings to Unix style (native on my platform) so it - wouldn't confuse other versioning systems used for project where libmv is bundled to, - - Also change mode to +x for glog's windows-related script. - -commit fe74ae2b53769389b0ed9d7e604c8e60be81077d -Author: Sergey I. Sharybin -Date: Sun Mar 11 20:34:15 2012 +0600 - - Replace "third_party/glog/src/glog/logging.h" with - - It was needed because of how build systems is setup in Blender but think - this will be helpful change for other applications too because it makes - it's easier to move libraries around and even use libraries installed - on the operation system. - -commit 37fc726701479f2d321d6af878fa93f3176278d5 -Author: Sergey I. Sharybin -Date: Sun Mar 11 19:27:41 2012 +0600 - - Upgrade gflags and glog libraries - stage 2 (final) - - Changes to upstream code which are needed to make libmv compile smooth on all platforms - - * Replace with "third_party/gflags/gflags/gflags.h" which is easier - to setup things in libmv and also helps with setting up building libmv into - external applications. - * Replace "glog/logging.h" and "glog/logging.h" with and - which is needed on Windows platform because otherwise files like logging.cc will be using - relative path which points to headers used by linux instead of headers need to be used - on Windows. - * Replace _asm int 3 with __debugbreak(). Such assembler code is obsolete and doesn't work - with 64bit versions of MSVC compilers. - * Do not use stacktrace for MinGW and FreeBSD because it leads into issues accessing - some specific data on this platforms. - * Define HAVE_LIB_GFLAGS for Windows builds. - * Do not define __declspec(dllimport) for MinGW platforms. - * Setup proper includes and datatypes for int32, uint32, int64 and uint64 for MinGW - * Do not define va_copy for MinGW platforms (it's already defined there). - * Patch localtime_r to be working fine with MinGW, disable strerror_r for MinGW because - of lack of needed functions. - -commit 8ed07abfa49d1e0511752021c972e0715e5a1383 -Author: Sergey I. Sharybin -Date: Sun Mar 11 19:06:33 2012 +0600 - - Upgrade gflags and glog libraries - stage 1 - - This commit copies sources from latest original release of gflags and glog - over currently bundled versions of this libraries without any modifications. - - This revision can't b compiled, all needed changes to make new libraries working - fine will be done with next commit to make it clear which changes were necessary - for easier bundling further newer version and extract patches and put them to - gflags/glog upstream repo. - - Such upgrade of libraries is needed to make it able to compile libmv - with clang compilers. Currently used versions: - - - gflags is version 2.0 - - glog is version 0.3.2 - -commit 75b9af405964ff2c7d3f0a44500e27e63b37c91b -Author: Sergey Sharybin -Date: Fri Feb 17 23:29:11 2012 +0600 - - _USE_MATH_DEFINES is needed to define constants like M_E when building with msvc - Occasionally was removed, but now added comment about this so hopefully it - wouldn't removed again. - -commit f85b1232a9b929f69443b5eed6e7a39908cd6551 -Author: Sergey Sharybin -Date: Fri Feb 17 21:34:40 2012 +0600 - - Picky edit: corrected mode for ssba readme file. - -commit f8c2b223f01551fd81a85f6d5221646165147035 -Author: Sergey Sharybin -Date: Fri Feb 17 21:32:05 2012 +0600 - - Picky edits: corrected EOL diff --git a/extern/libmv/SConscript b/extern/libmv/SConscript index a503730926d..d0015db42d7 100644 --- a/extern/libmv/SConscript +++ b/extern/libmv/SConscript @@ -11,7 +11,6 @@ Import('env') defs = [] -defs.append('V3DLIB_ENABLE_SUITESPARSE') defs.append('GOOGLE_GLOG_DLL_DECL=') src = env.Glob("*.cpp") diff --git a/extern/libmv/bundle.sh b/extern/libmv/bundle.sh index 21d0308268a..a9edfde55bf 100755 --- a/extern/libmv/bundle.sh +++ b/extern/libmv/bundle.sh @@ -124,7 +124,6 @@ cat > CMakeLists.txt << EOF set(INC . - ../colamd/Include third_party/ceres/include ) diff --git a/extern/libmv/patches/series b/extern/libmv/patches/series index 1db7983fdd0..e69de29bb2d 100644 --- a/extern/libmv/patches/series +++ b/extern/libmv/patches/series @@ -1 +0,0 @@ -v3d_verbosity.patch diff --git a/extern/libmv/patches/v3d_verbosity.patch b/extern/libmv/patches/v3d_verbosity.patch deleted file mode 100644 index f5c6afbd0b5..00000000000 --- a/extern/libmv/patches/v3d_verbosity.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/src/libmv/simple_pipeline/bundle.cc b/src/libmv/simple_pipeline/bundle.cc -index fa0b6cc..d382cd5 100644 ---- a/src/libmv/simple_pipeline/bundle.cc -+++ b/src/libmv/simple_pipeline/bundle.cc -@@ -194,7 +194,6 @@ void EuclideanBundleCommonIntrinsics(const Tracks &tracks, - double v3d_inlier_threshold = 500000.0; - - // Finally, run the bundle adjustment. -- V3D::optimizerVerbosenessLevel = 1; - V3D::CommonInternalsMetricBundleOptimizer opt(v3d_bundle_intrinsics, - v3d_inlier_threshold, - v3d_K, -- cgit v1.2.3