From 74e6e73f03a20bcd96098e42ec9137415197c2f8 Mon Sep 17 00:00:00 2001 From: dguittet Date: Mon, 24 Apr 2023 09:17:54 -0600 Subject: [PATCH 001/210] add or-tools to ssc --- .gitignore | 4 ++++ CMakeLists.txt | 28 ++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index defbddc53a..51e1332b2c 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,8 @@ bld/ build/ cmake-build-debug/ cmake-build-release/ +CMakeFiles +CMakeCache.txt test/Test # Visual Studio 2015 cache/options directory @@ -360,3 +362,5 @@ ssc/ssc\.exp ssc/sscd\.exp build_android/lib_oldssc.zip + +or-tools diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d7bfc8913..3ba4b02697 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,18 @@ option(SAM_SKIP_TESTS "Skips building tests" OFF) option(SAMAPI_EXPORT "Export of ssc binaries to the SAM_api directory; for Unix, compile ssc libraries for SAM_api" ON) +option(SKIP_ORTOOLS "Skips building OR-Tools" OFF) + +include(CMakeDependentOption) + +CMAKE_DEPENDENT_OPTION(BUILD_DEPS "Build OR-Tools dependencies" ON "NOT SKIP_ORTOOLS" OFF) +CMAKE_DEPENDENT_OPTION(USE_COINOR "Use the COIN-OR solver" OFF "NOT SKIP_ORTOOLS" OFF) +CMAKE_DEPENDENT_OPTION(USE_HIGHS "Use the HiGHS solver" OFF "NOT SKIP_ORTOOLS" OFF) +option(BUILD_EXAMPLES "Build examples" OFF) +option(BUILD_SAMPLES "Build samples" OFF) +CMAKE_DEPENDENT_OPTION(INSTALL_DOC "Install doc" OFF "NOT SKIP_ORTOOLS" OFF) + + # # If project isn't system_advisor_model and SAM_SKIP_TOOLS=1, # environment vars LK_LIB and LKD_LIB can be used to specify where to find those libraries @@ -26,8 +38,8 @@ if(APPLE) endif() if (UNIX AND NOT CMAKE_C_COMPILER) - set(CMAKE_C_COMPILER gcc) - set(CMAKE_CXX_COMPILER g++) + set(CMAKE_C_COMPILER gcc) + set(CMAKE_CXX_COMPILER g++) endif() set(CMAKE_CXX_STANDARD 11) @@ -142,17 +154,17 @@ endfunction() add_subdirectory(splinter) -add_subdirectory(shared) -add_subdirectory(nlopt) -add_subdirectory(lpsolve) -add_subdirectory(solarpilot) +if (NOT SKIP_ORTOOLS) + add_subdirectory(or-tools) + add_subdirectory(ortools_sandbox) +endif() add_subdirectory(tcs) add_subdirectory(ssc) if (NOT SAM_SKIP_TOOLS) - add_subdirectory(sdktool) + add_subdirectory(sdktool) endif() if (NOT SAM_SKIP_TESTS) - add_subdirectory(test) + add_subdirectory(test) endif() From 16965439ea98bdd8bd803fb42883725a6cfd3e26 Mon Sep 17 00:00:00 2001 From: dguittet Date: Tue, 13 Jun 2023 16:18:10 -0600 Subject: [PATCH 002/210] ortools_test working --- CMakeLists.txt | 8 +- shared/CMakeLists.txt | 9 +- shared/lib_mlmodel.cpp | 16 +- shared/lib_mlmodel.h | 5 +- shared/lib_ondinv.cpp | 17 +- shared/lib_ondinv.h | 19 +- shared/lib_ortools.cpp | 59 + shared/lib_ortools.h | 20 + shared/lib_ptes_chp_dispatch.cpp | 939 + shared/lib_ptes_chp_dispatch.h | 476 + splinter/CMakeLists.txt | 26 +- splinter/Geometry | 63 - splinter/SVD | 37 - splinter/bspline.cpp | 443 - splinter/bspline.h | 159 - splinter/bsplinebasis.cpp | 468 - splinter/bsplinebasis.h | 72 - splinter/bsplinebasis1d.cpp | 607 - splinter/bsplinebasis1d.h | 90 - splinter/bsplinebuilder.cpp | 558 - splinter/bsplinebuilder.h | 139 - splinter/datapoint.cpp | 93 - splinter/datapoint.h | 53 - splinter/datatable.cpp | 252 - splinter/datatable.h | 92 - splinter/function.cpp | 130 - splinter/function.h | 108 - splinter/include/bspline.h | 175 + splinter/include/bspline_basis.h | 73 + splinter/include/bspline_basis_1d.h | 101 + splinter/include/bspline_builders.h | 63 + splinter/include/bspline_utils.h | 37 + splinter/include/cinterface/cinterface.h | 399 + splinter/include/cinterface/utilities.h | 172 + splinter/include/data_point.h | 61 + splinter/include/data_table.h | 117 + splinter/{ => include}/definitions.h | 32 +- splinter/include/function.h | 95 + splinter/include/json.h | 17170 ++++++++++++++++ splinter/include/json_parser.h | 29 + splinter/include/knot_builders.h | 97 + splinter/include/knot_vector.h | 106 + .../kronecker_product.h} | 14 +- .../linear_solvers.h} | 66 +- splinter/include/utilities.h | 59 + splinter/knots.cpp | 70 - splinter/knots.h | 25 - splinter/saveable.h | 42 - splinter/serializer.cpp | 308 - splinter/serializer.h | 308 - splinter/src/Core/Assign.h | 590 - splinter/src/Core/Assign_MKL.h | 224 - splinter/src/Core/CoreIterators.h | 61 - splinter/src/Core/DenseStorage.h | 434 - splinter/src/Core/DiagonalProduct.h | 131 - splinter/src/Core/Flagged.h | 140 - splinter/src/Core/Functors.h | 1026 - splinter/src/Core/GeneralProduct.h | 638 - splinter/src/Core/GenericPacketMath.h | 350 - splinter/src/Core/GlobalFunctions.h | 92 - splinter/src/Core/MathFunctions.h | 768 - splinter/src/Core/ProductBase.h | 290 - splinter/src/Core/Reverse.h | 224 - splinter/src/Core/SelfAdjointView.h | 314 - splinter/src/Core/SelfCwiseBinaryOp.h | 191 - splinter/src/Core/Swap.h | 126 - splinter/src/Core/TriangularMatrix.h | 839 - splinter/src/Core/arch/AltiVec/Complex.h | 217 - splinter/src/Core/arch/AltiVec/PacketMath.h | 501 - splinter/src/Core/arch/NEON/Complex.h | 253 - splinter/src/Core/arch/NEON/PacketMath.h | 420 - .../src/Core/products/CoeffBasedProduct.h | 476 - .../Core/products/GeneralBlockPanelKernel.h | 1341 -- .../src/Core/products/GeneralMatrixMatrix.h | 433 - splinter/src/Core/util/Meta.h | 243 - .../src/Core/util/ReenableStupidWarnings.h | 14 - splinter/src/Core/util/XprHelper.h | 469 - splinter/src/Eigen2Support/Block.h | 126 - splinter/src/Eigen2Support/Cwise.h | 192 - splinter/src/Eigen2Support/CwiseOperators.h | 298 - .../src/Eigen2Support/Geometry/AlignedBox.h | 159 - splinter/src/Eigen2Support/Geometry/All.h | 115 - .../src/Eigen2Support/Geometry/AngleAxis.h | 214 - .../src/Eigen2Support/Geometry/Hyperplane.h | 254 - .../Eigen2Support/Geometry/ParametrizedLine.h | 141 - .../src/Eigen2Support/Geometry/Quaternion.h | 495 - .../src/Eigen2Support/Geometry/Rotation2D.h | 145 - .../src/Eigen2Support/Geometry/RotationBase.h | 123 - splinter/src/Eigen2Support/Geometry/Scaling.h | 167 - .../src/Eigen2Support/Geometry/Transform.h | 786 - .../src/Eigen2Support/Geometry/Translation.h | 184 - splinter/src/Eigen2Support/LU.h | 120 - splinter/src/Eigen2Support/Lazy.h | 71 - splinter/src/Eigen2Support/LeastSquares.h | 169 - splinter/src/Eigen2Support/Macros.h | 20 - splinter/src/Eigen2Support/MathFunctions.h | 57 - splinter/src/Eigen2Support/Memory.h | 45 - splinter/src/Eigen2Support/Meta.h | 75 - splinter/src/Eigen2Support/Minor.h | 117 - splinter/src/Eigen2Support/QR.h | 67 - splinter/src/Eigen2Support/SVD.h | 637 - splinter/src/Eigen2Support/TriangularSolver.h | 42 - splinter/src/Eigen2Support/VectorBlock.h | 94 - splinter/src/Geometry/Homogeneous.h | 307 - splinter/src/Householder/BlockHouseholder.h | 68 - .../IterativeSolverBase.h | 282 - splinter/src/SVD/JacobiSVD.h | 976 - splinter/src/SVD/UpperBidiagonalization.h | 148 - .../ConservativeSparseSparseProduct.h | 245 - splinter/src/SparseCore/MappedSparseMatrix.h | 181 - splinter/src/SparseCore/SparseBlock.h | 539 - splinter/src/SparseCore/SparseCwiseBinaryOp.h | 324 - splinter/src/SparseCore/SparseCwiseUnaryOp.h | 163 - splinter/src/SparseCore/SparseDenseProduct.h | 311 - .../src/SparseCore/SparseDiagonalProduct.h | 196 - splinter/src/SparseCore/SparseFuzzy.h | 26 - splinter/src/SparseCore/SparsePermutation.h | 148 - splinter/src/SparseCore/SparseProduct.h | 188 - .../src/SparseCore/SparseSelfAdjointView.h | 507 - splinter/src/SparseCore/SparseTranspose.h | 63 - .../src/SparseCore/SparseTriangularView.h | 179 - splinter/src/SparseCore/SparseView.h | 99 - splinter/src/bspline.cpp | 429 + splinter/src/bspline_basis.cpp | 456 + splinter/src/bspline_basis_1d.cpp | 574 + splinter/src/bspline_builders.cpp | 54 + splinter/src/bspline_utils.cpp | 296 + splinter/src/cinterface/bspline.cpp | 529 + splinter/src/cinterface/bspline_builders.cpp | 87 + splinter/src/cinterface/cinterface.cpp | 28 + splinter/src/cinterface/data_table.cpp | 166 + splinter/src/cinterface/utilities.cpp | 134 + splinter/src/data_point.cpp | 58 + splinter/src/data_table.cpp | 131 + splinter/src/function.cpp | 63 + splinter/src/json_parser.cpp | 146 + splinter/src/knot_builders.cpp | 213 + splinter/src/knot_vector.cpp | 105 + .../kronecker_product.cpp} | 22 +- splinter/src/misc/Solve.h | 76 - splinter/src/misc/SparseSolve.h | 128 - splinter/src/misc/blas.h | 658 - splinter/src/plugins/ArrayCwiseBinaryOps.h | 253 - splinter/src/plugins/ArrayCwiseUnaryOps.h | 187 - splinter/src/plugins/BlockMethods.h | 935 - splinter/src/plugins/CommonCwiseBinaryOps.h | 46 - splinter/src/plugins/CommonCwiseUnaryOps.h | 172 - splinter/src/plugins/MatrixCwiseUnaryOps.h | 52 - splinter/src/utilities.cpp | 109 + splinter/thirdparty/Catch/Catch.h | 9415 +++++++++ .../thirdparty/Eigen/Eigen/CMakeLists.txt | 19 + .../{ => thirdparty/Eigen/Eigen}/Cholesky | 22 +- .../thirdparty/Eigen/Eigen/CholmodSupport | 48 + splinter/{ => thirdparty/Eigen/Eigen}/Core | 311 +- splinter/thirdparty/Eigen/Eigen/Dense | 7 + splinter/thirdparty/Eigen/Eigen/Eigen | 2 + .../{ => thirdparty/Eigen/Eigen}/Eigenvalues | 19 +- splinter/thirdparty/Eigen/Eigen/Geometry | 62 + .../{ => thirdparty/Eigen/Eigen}/Householder | 7 + .../Eigen/Eigen}/IterativeLinearSolvers | 24 +- splinter/{ => thirdparty/Eigen/Eigen}/Jacobi | 7 + splinter/{ => thirdparty/Eigen/Eigen}/LU | 25 +- splinter/thirdparty/Eigen/Eigen/MetisSupport | 35 + .../Eigen/Eigen}/OrderingMethods | 7 + splinter/thirdparty/Eigen/Eigen/PaStiXSupport | 48 + .../thirdparty/Eigen/Eigen/PardisoSupport | 35 + splinter/{ => thirdparty/Eigen/Eigen}/QR | 28 +- .../thirdparty/Eigen/Eigen/QtAlignedMalloc | 40 + splinter/thirdparty/Eigen/Eigen/SPQRSupport | 34 + splinter/thirdparty/Eigen/Eigen/SVD | 51 + splinter/thirdparty/Eigen/Eigen/Sparse | 36 + .../Eigen/Eigen}/SparseCholesky | 2 - .../{ => thirdparty/Eigen/Eigen}/SparseCore | 33 +- .../{ => thirdparty/Eigen/Eigen}/SparseLU | 3 - .../{ => thirdparty/Eigen/Eigen}/SparseQR | 10 +- splinter/thirdparty/Eigen/Eigen/StdDeque | 27 + splinter/thirdparty/Eigen/Eigen/StdList | 26 + splinter/thirdparty/Eigen/Eigen/StdVector | 27 + .../thirdparty/Eigen/Eigen/SuperLUSupport | 64 + .../thirdparty/Eigen/Eigen/UmfPackSupport | 40 + .../Eigen/Eigen}/src/Cholesky/LDLT.h | 273 +- .../Eigen/Eigen}/src/Cholesky/LLT.h | 190 +- .../Eigen/Eigen/src/Cholesky/LLT_LAPACKE.h} | 45 +- .../src/CholmodSupport/CholmodSupport.h | 284 +- .../Eigen/Eigen}/src/Core/Array.h | 154 +- .../Eigen/Eigen}/src/Core/ArrayBase.h | 78 +- .../Eigen/Eigen}/src/Core/ArrayWrapper.h | 151 +- .../thirdparty/Eigen/Eigen/src/Core/Assign.h | 90 + .../Eigen/Eigen/src/Core/AssignEvaluator.h | 935 + .../Eigen/Eigen/src/Core/Assign_MKL.h | 178 + .../Eigen/Eigen}/src/Core/BandMatrix.h | 61 +- .../Eigen/Eigen}/src/Core/Block.h | 254 +- .../Eigen/Eigen}/src/Core/BooleanRedux.h | 42 +- .../Eigen/Eigen}/src/Core/CommaInitializer.h | 40 +- .../Eigen/Eigen/src/Core/ConditionEstimator.h | 175 + .../Eigen/Eigen/src/Core/CoreEvaluators.h | 1688 ++ .../Eigen/Eigen/src/Core/CoreIterators.h | 127 + .../Eigen/Eigen}/src/Core/CwiseBinaryOp.h | 166 +- .../Eigen/Eigen}/src/Core/CwiseNullaryOp.h | 322 +- .../Eigen/Eigen/src/Core/CwiseTernaryOp.h | 197 + .../Eigen/Eigen}/src/Core/CwiseUnaryOp.h | 111 +- .../Eigen/Eigen}/src/Core/CwiseUnaryView.h | 81 +- .../Eigen/Eigen}/src/Core/DenseBase.h | 388 +- .../Eigen/Eigen}/src/Core/DenseCoeffsBase.h | 279 +- .../Eigen/Eigen/src/Core/DenseStorage.h | 570 + .../Eigen/Eigen}/src/Core/Diagonal.h | 69 +- .../Eigen/Eigen}/src/Core/DiagonalMatrix.h | 140 +- .../Eigen/Eigen/src/Core/DiagonalProduct.h | 28 + .../Eigen/Eigen}/src/Core/Dot.h | 173 +- .../Eigen/Eigen}/src/Core/EigenBase.h | 52 +- .../Eigen}/src/Core/ForceAlignedAccess.h | 24 +- .../Eigen/Eigen}/src/Core/Fuzzy.h | 13 +- .../Eigen/Eigen/src/Core/GeneralProduct.h | 455 + .../Eigen/Eigen/src/Core/GenericPacketMath.h | 593 + .../Eigen/Eigen/src/Core/GlobalFunctions.h | 187 + .../Eigen/Eigen}/src/Core/IO.h | 49 +- .../thirdparty/Eigen/Eigen/src/Core/Inverse.h | 118 + .../Eigen/Eigen}/src/Core/Map.h | 125 +- .../Eigen/Eigen}/src/Core/MapBase.h | 98 +- .../Eigen/Eigen/src/Core/MathFunctions.h | 1407 ++ .../Eigen/Eigen/src/Core/MathFunctionsImpl.h | 101 + .../Eigen/Eigen}/src/Core/Matrix.h | 241 +- .../Eigen/Eigen}/src/Core/MatrixBase.h | 308 +- .../Eigen/Eigen}/src/Core/NestByValue.h | 35 +- .../Eigen/Eigen}/src/Core/NoAlias.h | 62 +- .../Eigen/Eigen}/src/Core/NumTraits.h | 138 +- .../Eigen/Eigen}/src/Core/PermutationMatrix.h | 364 +- .../Eigen/Eigen}/src/Core/PlainObjectBase.h | 431 +- .../thirdparty/Eigen/Eigen/src/Core/Product.h | 186 + .../Eigen/Eigen/src/Core/ProductEvaluators.h | 1112 + .../Eigen/Eigen}/src/Core/Random.h | 58 +- .../Eigen/Eigen}/src/Core/Redux.h | 210 +- .../Eigen/Eigen}/src/Core/Ref.h | 201 +- .../Eigen/Eigen}/src/Core/Replicate.h | 95 +- .../Eigen/Eigen}/src/Core/ReturnByValue.h | 50 +- .../thirdparty/Eigen/Eigen/src/Core/Reverse.h | 211 + .../Eigen/Eigen}/src/Core/Select.h | 22 +- .../Eigen/Eigen/src/Core/SelfAdjointView.h | 352 + .../Eigen/Eigen/src/Core/SelfCwiseBinaryOp.h | 47 + .../thirdparty/Eigen/Eigen/src/Core/Solve.h | 188 + .../Eigen/Eigen}/src/Core/SolveTriangular.h | 76 +- .../Eigen/Eigen/src/Core/SolverBase.h | 130 + .../Eigen/Eigen}/src/Core/StableNorm.h | 54 +- .../Eigen/Eigen}/src/Core/Stride.h | 25 +- .../thirdparty/Eigen/Eigen/src/Core/Swap.h | 67 + .../Eigen/Eigen}/src/Core/Transpose.h | 184 +- .../Eigen/Eigen}/src/Core/Transpositions.h | 245 +- .../Eigen/Eigen/src/Core/TriangularMatrix.h | 983 + .../Eigen/Eigen}/src/Core/VectorBlock.h | 27 +- .../Eigen/Eigen}/src/Core/VectorwiseOp.h | 339 +- .../Eigen/Eigen}/src/Core/Visitor.h | 77 +- .../Eigen/Eigen/src/Core/arch/AVX/Complex.h | 451 + .../Eigen/src/Core/arch/AVX/MathFunctions.h | 439 + .../Eigen/src/Core/arch/AVX/PacketMath.h | 636 + .../Eigen/src/Core/arch/AVX/TypeCasting.h | 51 + .../src/Core/arch/AVX512/MathFunctions.h | 391 + .../Eigen/src/Core/arch/AVX512/PacketMath.h | 1316 ++ .../Eigen/src/Core/arch/AltiVec/Complex.h | 430 + .../src/Core/arch/AltiVec/MathFunctions.h | 322 + .../Eigen/src/Core/arch/AltiVec/PacketMath.h | 1061 + .../Eigen/Eigen/src/Core/arch/CUDA/Complex.h | 103 + .../Eigen/Eigen/src/Core/arch/CUDA/Half.h | 651 + .../Eigen/src/Core/arch/CUDA/MathFunctions.h | 91 + .../Eigen/src/Core/arch/CUDA/PacketMath.h | 333 + .../Eigen/src/Core/arch/CUDA/PacketMathHalf.h | 1123 + .../Eigen/src/Core/arch/CUDA/TypeCasting.h | 212 + .../Eigen/src/Core/arch/Default/ConjHelper.h | 29 + .../Eigen}/src/Core/arch/Default/Settings.h | 0 .../Eigen/Eigen/src/Core/arch/NEON/Complex.h | 490 + .../Eigen/src/Core/arch/NEON/MathFunctions.h | 91 + .../Eigen/src/Core/arch/NEON/PacketMath.h | 760 + .../Eigen/Eigen}/src/Core/arch/SSE/Complex.h | 131 +- .../Eigen}/src/Core/arch/SSE/MathFunctions.h | 113 +- .../Eigen}/src/Core/arch/SSE/PacketMath.h | 438 +- .../Eigen/src/Core/arch/SSE/TypeCasting.h | 77 + .../Eigen/src/Core/arch/ZVector/Complex.h | 397 + .../src/Core/arch/ZVector/MathFunctions.h | 137 + .../Eigen/src/Core/arch/ZVector/PacketMath.h | 945 + .../src/Core/functors/AssignmentFunctors.h | 168 + .../Eigen/src/Core/functors/BinaryFunctors.h | 475 + .../Eigen/src/Core/functors/NullaryFunctors.h | 188 + .../Eigen/src/Core/functors/StlFunctors.h | 136 + .../Eigen/src/Core/functors/TernaryFunctors.h | 25 + .../Eigen/src/Core/functors/UnaryFunctors.h | 792 + .../Core/products/GeneralBlockPanelKernel.h | 2149 ++ .../src/Core/products/GeneralMatrixMatrix.h | 492 + .../products/GeneralMatrixMatrixTriangular.h | 145 +- .../GeneralMatrixMatrixTriangular_BLAS.h} | 73 +- .../Core/products/GeneralMatrixMatrix_BLAS.h} | 54 +- .../src/Core/products/GeneralMatrixVector.h | 305 +- .../Core/products/GeneralMatrixVector_BLAS.h} | 75 +- .../Eigen}/src/Core/products/Parallelizer.h | 67 +- .../Core/products/SelfadjointMatrixMatrix.h | 335 +- .../products/SelfadjointMatrixMatrix_BLAS.h} | 152 +- .../Core/products/SelfadjointMatrixVector.h | 127 +- .../products/SelfadjointMatrixVector_BLAS.h} | 56 +- .../src/Core/products/SelfadjointProduct.h | 26 +- .../Core/products/SelfadjointRank2Update.h | 8 +- .../Core/products/TriangularMatrixMatrix.h | 163 +- .../products/TriangularMatrixMatrix_BLAS.h} | 126 +- .../Core/products/TriangularMatrixVector.h | 196 +- .../products/TriangularMatrixVector_BLAS.h} | 110 +- .../Core/products/TriangularSolverMatrix.h | 73 +- .../products/TriangularSolverMatrix_BLAS.h} | 72 +- .../Core/products/TriangularSolverVector.h | 24 +- .../Eigen/Eigen}/src/Core/util/BlasUtil.h | 204 +- .../Eigen/Eigen}/src/Core/util/Constants.h | 174 +- .../src/Core/util/DisableStupidWarnings.h | 39 +- .../src/Core/util/ForwardDeclarations.h | 134 +- .../Eigen/Eigen}/src/Core/util/MKL_support.h | 54 +- .../Eigen/Eigen}/src/Core/util/Macros.h | 553 +- .../Eigen/Eigen}/src/Core/util/Memory.h | 574 +- .../Eigen/Eigen/src/Core/util/Meta.h | 512 + .../Eigen/Eigen}/src/Core/util/NonMPL2.h | 0 .../src/Core/util/ReenableStupidWarnings.h | 27 + .../Eigen/Eigen}/src/Core/util/StaticAssert.h | 140 +- .../Eigen/Eigen/src/Core/util/XprHelper.h | 821 + .../src/Eigenvalues/ComplexEigenSolver.h | 25 +- .../Eigen}/src/Eigenvalues/ComplexSchur.h | 19 +- .../src/Eigenvalues/ComplexSchur_LAPACKE.h} | 40 +- .../Eigen}/src/Eigenvalues/EigenSolver.h | 113 +- .../src/Eigenvalues/GeneralizedEigenSolver.h | 196 +- .../GeneralizedSelfAdjointEigenSolver.h | 3 +- .../src/Eigenvalues/HessenbergDecomposition.h | 15 +- .../src/Eigenvalues/MatrixBaseEigenvalues.h | 0 .../Eigen/Eigen}/src/Eigenvalues/RealQZ.h | 46 +- .../Eigen/Eigen}/src/Eigenvalues/RealSchur.h | 45 +- .../src/Eigenvalues/RealSchur_LAPACKE.h} | 38 +- .../src/Eigenvalues/SelfAdjointEigenSolver.h | 273 +- .../SelfAdjointEigenSolver_LAPACKE.h} | 41 +- .../src/Eigenvalues/Tridiagonalization.h | 39 +- .../Eigen/Eigen}/src/Geometry/AlignedBox.h | 96 +- .../Eigen/Eigen}/src/Geometry/AngleAxis.h | 85 +- .../Eigen/Eigen}/src/Geometry/EulerAngles.h | 22 +- .../Eigen/Eigen/src/Geometry/Homogeneous.h | 497 + .../Eigen/Eigen}/src/Geometry/Hyperplane.h | 64 +- .../Eigen/Eigen}/src/Geometry/OrthoMethods.h | 58 +- .../Eigen}/src/Geometry/ParametrizedLine.h | 60 +- .../Eigen/Eigen}/src/Geometry/Quaternion.h | 240 +- .../Eigen/Eigen}/src/Geometry/Rotation2D.h | 85 +- .../Eigen/Eigen}/src/Geometry/RotationBase.h | 48 +- .../Eigen/Eigen}/src/Geometry/Scaling.h | 38 +- .../Eigen/Eigen}/src/Geometry/Transform.h | 262 +- .../Eigen/Eigen}/src/Geometry/Translation.h | 60 +- .../Eigen/Eigen}/src/Geometry/Umeyama.h | 19 +- .../Eigen}/src/Geometry/arch/Geometry_SSE.h | 86 +- .../Eigen/src/Householder/BlockHouseholder.h | 103 + .../Eigen}/src/Householder/Householder.h | 7 +- .../src/Householder/HouseholderSequence.h | 55 +- .../BasicPreconditioners.h | 129 +- .../src/IterativeLinearSolvers/BiCGSTAB.h | 97 +- .../ConjugateGradient.h | 137 +- .../IncompleteCholesky.h | 400 + .../IterativeLinearSolvers/IncompleteLUT.h | 138 +- .../IterativeSolverBase.h | 394 + .../LeastSquareConjugateGradient.h | 216 + .../IterativeLinearSolvers/SolveWithGuess.h | 115 + .../Eigen/Eigen}/src/Jacobi/Jacobi.h | 250 +- .../Eigen/Eigen}/src/LU/Determinant.h | 2 +- .../Eigen/Eigen}/src/LU/FullPivLU.h | 314 +- .../Eigen/Eigen/src/LU/InverseImpl.h} | 81 +- .../Eigen/Eigen}/src/LU/PartialPivLU.h | 252 +- .../Eigen/src/LU/PartialPivLU_LAPACKE.h} | 26 +- .../Eigen/Eigen}/src/LU/arch/Inverse_SSE.h | 47 +- .../Eigen}/src/MetisSupport/MetisSupport.h | 18 +- .../Eigen/Eigen}/src/OrderingMethods/Amd.h | 83 +- .../Eigen}/src/OrderingMethods/Eigen_Colamd.h | 412 +- .../Eigen}/src/OrderingMethods/Ordering.h | 51 +- .../Eigen}/src/PaStiXSupport/PaStiXSupport.h | 163 +- .../src/PardisoSupport/PardisoSupport.h | 249 +- .../Eigen/Eigen}/src/QR/ColPivHouseholderQR.h | 281 +- .../src/QR/ColPivHouseholderQR_LAPACKE.h} | 47 +- .../src/QR/CompleteOrthogonalDecomposition.h | 562 + .../Eigen}/src/QR/FullPivHouseholderQR.h | 192 +- .../Eigen/Eigen}/src/QR/HouseholderQR.h | 119 +- .../Eigen/src/QR/HouseholderQR_LAPACKE.h} | 29 +- .../src/SPQRSupport/SuiteSparseQRSupport.h | 123 +- .../thirdparty/Eigen/Eigen/src/SVD/BDCSVD.h | 1246 ++ .../Eigen}/Eigen/src/SVD/JacobiSVD.h | 350 +- .../Eigen/Eigen/src/SVD/JacobiSVD_LAPACKE.h} | 51 +- .../Eigen}/Eigen/src/SVD/SVDBase.h | 199 +- .../Eigen/src/SVD/UpperBidiagonalization.h | 414 + .../src/SparseCholesky/SimplicialCholesky.h | 272 +- .../SparseCholesky/SimplicialCholesky_impl.h | 34 +- .../Eigen/Eigen}/src/SparseCore/AmbiVector.h | 100 +- .../Eigen}/src/SparseCore/CompressedStorage.h | 139 +- .../ConservativeSparseSparseProduct.h | 352 + .../Eigen/src/SparseCore/MappedSparseMatrix.h | 67 + .../Eigen/Eigen/src/SparseCore/SparseAssign.h | 216 + .../Eigen/Eigen/src/SparseCore/SparseBlock.h | 603 + .../Eigen}/src/SparseCore/SparseColEtree.h | 44 +- .../src/SparseCore/SparseCompressedBase.h | 341 + .../src/SparseCore/SparseCwiseBinaryOp.h | 726 + .../Eigen/src/SparseCore/SparseCwiseUnaryOp.h | 148 + .../Eigen/src/SparseCore/SparseDenseProduct.h | 320 + .../src/SparseCore/SparseDiagonalProduct.h | 138 + .../Eigen/Eigen}/src/SparseCore/SparseDot.h | 17 +- .../Eigen/Eigen/src/SparseCore/SparseFuzzy.h | 29 + .../Eigen/Eigen/src/SparseCore/SparseMap.h | 305 + .../Eigen}/src/SparseCore/SparseMatrix.h | 641 +- .../Eigen}/src/SparseCore/SparseMatrixBase.h | 268 +- .../Eigen/src/SparseCore/SparsePermutation.h | 178 + .../Eigen/src/SparseCore/SparseProduct.h | 169 + .../Eigen/Eigen}/src/SparseCore/SparseRedux.h | 12 +- .../Eigen/Eigen/src/SparseCore/SparseRef.h | 397 + .../src/SparseCore/SparseSelfAdjointView.h | 656 + .../Eigen/src/SparseCore/SparseSolverBase.h | 124 + .../SparseSparseProductWithPruning.h | 92 +- .../Eigen/src/SparseCore/SparseTranspose.h | 92 + .../src/SparseCore/SparseTriangularView.h | 189 + .../Eigen/Eigen}/src/SparseCore/SparseUtil.h | 106 +- .../Eigen}/src/SparseCore/SparseVector.h | 212 +- .../Eigen/Eigen/src/SparseCore/SparseView.h | 253 + .../Eigen}/src/SparseCore/TriangularSolver.h | 117 +- .../Eigen/Eigen}/src/SparseLU/SparseLU.h | 221 +- .../Eigen/Eigen}/src/SparseLU/SparseLUImpl.h | 10 +- .../Eigen}/src/SparseLU/SparseLU_Memory.h | 15 +- .../Eigen}/src/SparseLU/SparseLU_Structs.h | 3 +- .../src/SparseLU/SparseLU_SupernodalMatrix.h | 69 +- .../Eigen}/src/SparseLU/SparseLU_Utils.h | 10 +- .../src/SparseLU/SparseLU_column_bmod.h | 7 +- .../Eigen}/src/SparseLU/SparseLU_column_dfs.h | 38 +- .../src/SparseLU/SparseLU_copy_to_ucol.h | 7 +- .../src/SparseLU/SparseLU_gemm_kernel.h | 93 +- .../src/SparseLU/SparseLU_heap_relax_snode.h | 21 +- .../src/SparseLU/SparseLU_kernel_bmod.h | 52 +- .../Eigen}/src/SparseLU/SparseLU_panel_bmod.h | 6 +- .../Eigen}/src/SparseLU/SparseLU_panel_dfs.h | 44 +- .../Eigen}/src/SparseLU/SparseLU_pivotL.h | 12 +- .../Eigen}/src/SparseLU/SparseLU_pruneL.h | 7 +- .../src/SparseLU/SparseLU_relax_snode.h | 12 +- .../Eigen/Eigen}/src/SparseQR/SparseQR.h | 211 +- .../Eigen/Eigen}/src/StlSupport/StdDeque.h | 2 +- .../Eigen/Eigen}/src/StlSupport/StdList.h | 4 +- .../Eigen/Eigen}/src/StlSupport/StdVector.h | 5 + .../Eigen/Eigen}/src/StlSupport/details.h | 16 +- .../src/SuperLUSupport/SuperLUSupport.h | 209 +- .../src/UmfPackSupport/UmfPackSupport.h | 314 +- .../Eigen/Eigen}/src/misc/Image.h | 2 - .../Eigen/Eigen}/src/misc/Kernel.h | 4 +- .../Eigen/Eigen/src/misc/RealSvd2x2.h | 55 + .../thirdparty/Eigen/Eigen/src/misc/blas.h | 440 + .../thirdparty/Eigen/Eigen/src/misc/lapack.h | 152 + .../thirdparty/Eigen/Eigen/src/misc/lapacke.h | 16291 +++++++++++++++ .../Eigen/Eigen/src/misc/lapacke_mangling.h | 17 + .../Eigen/src/plugins/ArrayCwiseBinaryOps.h | 332 + .../Eigen/src/plugins/ArrayCwiseUnaryOps.h | 552 + .../Eigen/Eigen/src/plugins/BlockMethods.h | 1058 + .../Eigen/src/plugins/CommonCwiseBinaryOps.h | 115 + .../Eigen/src/plugins/CommonCwiseUnaryOps.h | 163 + .../Eigen}/src/plugins/MatrixCwiseBinaryOps.h | 29 +- .../Eigen/src/plugins/MatrixCwiseUnaryOps.h | 85 + .../Eigen/unsupported/CMakeLists.txt | 9 + .../Eigen}/unsupported/Eigen/AdolcForward | 2 +- .../Eigen}/unsupported/Eigen/AlignedVector3 | 38 +- .../Eigen}/unsupported/Eigen/ArpackSupport | 0 .../Eigen}/unsupported/Eigen/AutoDiff | 0 .../Eigen}/unsupported/Eigen/BVH | 0 .../Eigen/unsupported/Eigen/CMakeLists.txt | 32 + .../unsupported/Eigen/CXX11/CMakeLists.txt | 8 + .../Eigen/unsupported/Eigen/CXX11/Tensor | 152 + .../unsupported/Eigen/CXX11/TensorSymmetry | 42 + .../Eigen/unsupported/Eigen/CXX11/ThreadPool | 65 + .../Eigen/CXX11/src/Tensor/README.md | 1757 ++ .../Eigen/CXX11/src/Tensor/Tensor.h | 527 + .../Eigen/CXX11/src/Tensor/TensorArgMax.h | 299 + .../Eigen/CXX11/src/Tensor/TensorAssign.h | 181 + .../Eigen/CXX11/src/Tensor/TensorBase.h | 1010 + .../CXX11/src/Tensor/TensorBroadcasting.h | 392 + .../Eigen/CXX11/src/Tensor/TensorChipping.h | 384 + .../CXX11/src/Tensor/TensorConcatenation.h | 361 + .../CXX11/src/Tensor/TensorContraction.h | 628 + .../src/Tensor/TensorContractionBlocking.h | 56 + .../CXX11/src/Tensor/TensorContractionCuda.h | 1391 ++ .../src/Tensor/TensorContractionMapper.h | 467 + .../src/Tensor/TensorContractionThreadPool.h | 1052 + .../Eigen/CXX11/src/Tensor/TensorConversion.h | 279 + .../CXX11/src/Tensor/TensorConvolution.h | 1104 + .../Eigen/CXX11/src/Tensor/TensorCostModel.h | 212 + .../Eigen/CXX11/src/Tensor/TensorCustomOp.h | 313 + .../Eigen/CXX11/src/Tensor/TensorDevice.h | 68 + .../Eigen/CXX11/src/Tensor/TensorDeviceCuda.h | 337 + .../CXX11/src/Tensor/TensorDeviceDefault.h | 81 + .../Eigen/CXX11/src/Tensor/TensorDeviceSycl.h | 122 + .../CXX11/src/Tensor/TensorDeviceThreadPool.h | 282 + .../CXX11/src/Tensor/TensorDimensionList.h | 236 + .../Eigen/CXX11/src/Tensor/TensorDimensions.h | 428 + .../Eigen/CXX11/src/Tensor/TensorEvalTo.h | 181 + .../Eigen/CXX11/src/Tensor/TensorEvaluator.h | 633 + .../Eigen/CXX11/src/Tensor/TensorExecutor.h | 288 + .../Eigen/CXX11/src/Tensor/TensorExpr.h | 371 + .../Eigen/CXX11/src/Tensor/TensorFFT.h | 651 + .../Eigen/CXX11/src/Tensor/TensorFixedSize.h | 389 + .../Eigen/CXX11/src/Tensor/TensorForcedEval.h | 167 + .../src/Tensor/TensorForwardDeclarations.h | 109 + .../Eigen/CXX11/src/Tensor/TensorFunctors.h | 489 + .../Eigen/CXX11/src/Tensor/TensorGenerator.h | 185 + .../CXX11/src/Tensor/TensorGlobalFunctions.h | 33 + .../Eigen/CXX11/src/Tensor/TensorIO.h | 79 + .../Eigen/CXX11/src/Tensor/TensorImagePatch.h | 509 + .../Eigen/CXX11/src/Tensor/TensorIndexList.h | 725 + .../Eigen/CXX11/src/Tensor/TensorInflation.h | 229 + .../CXX11/src/Tensor/TensorInitializer.h | 82 + .../Eigen/CXX11/src/Tensor/TensorIntDiv.h | 253 + .../Eigen/CXX11/src/Tensor/TensorLayoutSwap.h | 209 + .../Eigen/CXX11/src/Tensor/TensorMacros.h | 54 + .../Eigen/CXX11/src/Tensor/TensorMap.h | 321 + .../Eigen/CXX11/src/Tensor/TensorMeta.h | 218 + .../Eigen/CXX11/src/Tensor/TensorMorphing.h | 888 + .../Eigen/CXX11/src/Tensor/TensorPadding.h | 397 + .../Eigen/CXX11/src/Tensor/TensorPatch.h | 269 + .../Eigen/CXX11/src/Tensor/TensorRandom.h | 276 + .../Eigen/CXX11/src/Tensor/TensorReduction.h | 781 + .../CXX11/src/Tensor/TensorReductionCuda.h | 750 + .../CXX11/src/Tensor/TensorReductionSycl.h | 242 + .../Eigen/CXX11/src/Tensor/TensorRef.h | 429 + .../Eigen/CXX11/src/Tensor/TensorReverse.h | 288 + .../Eigen/CXX11/src/Tensor/TensorScan.h | 287 + .../Eigen/CXX11/src/Tensor/TensorShuffling.h | 264 + .../Eigen/CXX11/src/Tensor/TensorStorage.h | 146 + .../Eigen/CXX11/src/Tensor/TensorStriding.h | 338 + .../Eigen/CXX11/src/Tensor/TensorSycl.h | 82 + .../TensorSyclConvertToDeviceExpression.h | 121 + .../src/Tensor/TensorSyclExprConstructor.h | 239 + .../src/Tensor/TensorSyclExtractAccessor.h | 204 + .../src/Tensor/TensorSyclExtractFunctors.h | 177 + .../CXX11/src/Tensor/TensorSyclLeafCount.h | 114 + .../src/Tensor/TensorSyclPlaceHolderExpr.h | 181 + .../Eigen/CXX11/src/Tensor/TensorSyclRun.h | 70 + .../Eigen/CXX11/src/Tensor/TensorSyclTuple.h | 234 + .../Eigen/CXX11/src/Tensor/TensorTraits.h | 272 + .../Eigen/CXX11/src/Tensor/TensorUInt128.h | 248 + .../CXX11/src/Tensor/TensorVolumePatch.h | 608 + .../src/TensorSymmetry/DynamicSymmetry.h | 293 + .../CXX11/src/TensorSymmetry/StaticSymmetry.h | 236 + .../Eigen/CXX11/src/TensorSymmetry/Symmetry.h | 338 + .../TensorSymmetry/util/TemplateGroupTheory.h | 666 + .../Eigen/CXX11/src/ThreadPool/EventCount.h | 233 + .../src/ThreadPool/NonBlockingThreadPool.h | 274 + .../Eigen/CXX11/src/ThreadPool/RunQueue.h | 210 + .../CXX11/src/ThreadPool/SimpleThreadPool.h | 154 + .../CXX11/src/ThreadPool/ThreadEnvironment.h | 38 + .../Eigen/CXX11/src/ThreadPool/ThreadLocal.h | 22 + .../src/ThreadPool/ThreadPoolInterface.h | 33 + .../Eigen/CXX11/src/ThreadPool/ThreadYield.h | 20 + .../Eigen/CXX11/src/util/CXX11Meta.h | 542 + .../Eigen/CXX11/src/util/CXX11Workarounds.h | 88 + .../Eigen/CXX11/src/util/EmulateArray.h | 267 + .../Eigen/CXX11/src/util/EmulateCXX11Meta.h | 311 + .../Eigen/CXX11/src/util/MaxSizeVector.h | 141 + .../Eigen/unsupported/Eigen/EulerAngles | 43 + .../Eigen}/unsupported/Eigen/FFT | 0 .../Eigen}/unsupported/Eigen/IterativeSolvers | 5 +- .../Eigen}/unsupported/Eigen/KroneckerProduct | 8 +- .../unsupported/Eigen/LevenbergMarquardt | 0 .../Eigen}/unsupported/Eigen/MPRealSupport | 104 +- .../Eigen}/unsupported/Eigen/MatrixFunctions | 76 +- .../unsupported/Eigen/MoreVectorization | 0 .../unsupported/Eigen/NonLinearOptimization | 0 .../Eigen}/unsupported/Eigen/NumericalDiff | 0 .../Eigen}/unsupported/Eigen/OpenGLSupport | 20 +- .../Eigen}/unsupported/Eigen/Polynomials | 0 .../Eigen}/unsupported/Eigen/Skyline | 0 .../Eigen}/unsupported/Eigen/SparseExtra | 3 - .../Eigen/unsupported/Eigen/SpecialFunctions | 63 + .../Eigen}/unsupported/Eigen/Splines | 0 .../Eigen/src/AutoDiff/AutoDiffJacobian.h | 49 +- .../Eigen/src/AutoDiff/AutoDiffScalar.h | 231 +- .../Eigen/src/AutoDiff/AutoDiffVector.h | 0 .../unsupported/Eigen/src/BVH/BVAlgorithms.h | 0 .../Eigen}/unsupported/Eigen/src/BVH/KdBVH.h | 0 .../ArpackSelfAdjointEigenSolver.h | 14 +- .../Eigen/src/EulerAngles/CMakeLists.txt | 6 + .../Eigen/src/EulerAngles/EulerAngles.h | 386 + .../Eigen/src/EulerAngles/EulerSystem.h | 326 + .../unsupported/Eigen/src/FFT/ei_fftw_impl.h | 0 .../Eigen/src/FFT/ei_kissfft_impl.h | 0 .../IterativeSolvers/ConstrainedConjGrad.h | 0 .../Eigen/src/IterativeSolvers/DGMRES.h | 113 +- .../Eigen/src/IterativeSolvers/GMRES.h | 343 + .../Eigen/src/IterativeSolvers/IncompleteLU.h | 39 +- .../IterativeSolvers/IterationController.h | 0 .../Eigen/src/IterativeSolvers/MINRES.h | 84 +- .../Eigen/src/IterativeSolvers/Scaling.h | 6 +- .../KroneckerProduct/KroneckerTensorProduct.h | 169 +- .../LevenbergMarquardt/CopyrightMINPACK.txt | 0 .../Eigen/src/LevenbergMarquardt/LMcovar.h | 1 - .../Eigen/src/LevenbergMarquardt/LMonestep.h | 0 .../Eigen/src/LevenbergMarquardt/LMpar.h | 2 +- .../Eigen/src/LevenbergMarquardt/LMqrsolv.h | 9 +- .../LevenbergMarquardt/LevenbergMarquardt.h | 31 +- .../src/MatrixFunctions/MatrixExponential.h | 441 + .../src/MatrixFunctions/MatrixFunction.h | 580 + .../src/MatrixFunctions/MatrixLogarithm.h | 373 + .../Eigen/src/MatrixFunctions/MatrixPower.h | 397 +- .../src/MatrixFunctions/MatrixSquareRoot.h | 370 + .../Eigen/src/MatrixFunctions/StemFunction.h | 117 + .../src/MoreVectorization/MathFunctions.h | 0 .../HybridNonLinearSolver.h | 4 +- .../LevenbergMarquardt.h | 25 +- .../Eigen/src/NonLinearOptimization/chkder.h | 0 .../Eigen/src/NonLinearOptimization/covar.h | 0 .../Eigen/src/NonLinearOptimization/dogleg.h | 0 .../Eigen/src/NonLinearOptimization/fdjac1.h | 0 .../Eigen/src/NonLinearOptimization/lmpar.h | 0 .../Eigen/src/NonLinearOptimization/qrsolv.h | 0 .../Eigen/src/NonLinearOptimization/r1mpyq.h | 0 .../Eigen/src/NonLinearOptimization/r1updt.h | 0 .../Eigen/src/NonLinearOptimization/rwupdt.h | 0 .../Eigen/src/NumericalDiff/NumericalDiff.h | 0 .../Eigen/src/Polynomials/Companion.h | 0 .../Eigen/src/Polynomials/PolynomialSolver.h | 33 +- .../Eigen/src/Polynomials/PolynomialUtils.h | 2 +- .../Eigen/src/Skyline/SkylineInplaceLU.h | 0 .../Eigen/src/Skyline/SkylineMatrix.h | 0 .../Eigen/src/Skyline/SkylineMatrixBase.h | 0 .../Eigen/src/Skyline/SkylineProduct.h | 6 +- .../Eigen/src/Skyline/SkylineStorage.h | 0 .../Eigen/src/Skyline/SkylineUtil.h | 0 .../SparseExtra/BlockOfDynamicSparseMatrix.h | 0 .../Eigen/src/SparseExtra/BlockSparseMatrix.h | 1079 + .../src/SparseExtra/DynamicSparseMatrix.h | 71 +- .../Eigen/src/SparseExtra/MarketIO.h | 22 +- .../src/SparseExtra/MatrixMarketIterator.h | 43 +- .../Eigen/src/SparseExtra/RandomSetter.h | 10 +- .../SpecialFunctionsArrayAPI.h | 124 + .../SpecialFunctionsFunctors.h | 236 + .../SpecialFunctions/SpecialFunctionsHalf.h | 47 + .../SpecialFunctions/SpecialFunctionsImpl.h | 1565 ++ .../SpecialFunctionsPacketMath.h | 58 + .../arch/CUDA/CudaSpecialFunctions.h | 165 + .../unsupported/Eigen/src/Splines/Spline.h | 74 +- .../Eigen/src/Splines/SplineFitting.h | 430 + .../unsupported/Eigen/src/Splines/SplineFwd.h | 11 +- .../thirdparty/Eigen/unsupported/README.txt | 50 + .../Eigen}/unsupported/bench/bench_svd.cpp | 0 .../Eigen/unsupported/doc/CMakeLists.txt | 4 + .../Eigen/unsupported/doc/Overview.dox | 28 + .../unsupported/doc/eigendoxy_layout.xml.in | 177 + .../unsupported/doc/examples/BVH_Example.cpp | 50 + .../unsupported/doc/examples/CMakeLists.txt | 20 + .../unsupported/doc/examples/EulerAngles.cpp | 46 + .../Eigen/unsupported/doc/examples/FFT.cpp | 118 + .../doc/examples/MatrixExponential.cpp | 16 + .../doc/examples/MatrixFunction.cpp | 23 + .../doc/examples/MatrixLogarithm.cpp | 15 + .../unsupported/doc/examples/MatrixPower.cpp | 16 + .../doc/examples/MatrixPower_optimal.cpp | 17 + .../unsupported/doc/examples/MatrixSine.cpp | 20 + .../unsupported/doc/examples/MatrixSinh.cpp | 20 + .../doc/examples/MatrixSquareRoot.cpp | 16 + .../doc/examples/PolynomialSolver1.cpp | 53 + .../doc/examples/PolynomialUtils1.cpp | 20 + .../unsupported/doc/snippets/CMakeLists.txt | 26 + .../thirdparty/Eigen/unsupported/test/BVH.cpp | 222 + .../Eigen/unsupported/test/CMakeLists.txt | 262 + .../Eigen/unsupported/test/EulerAngles.cpp | 208 + .../thirdparty/Eigen/unsupported/test/FFT.cpp | 2 + .../Eigen/unsupported/test/FFTW.cpp | 262 + .../test/NonLinearOptimization.cpp | 1878 ++ .../Eigen/unsupported/test/NumericalDiff.cpp | 114 + .../Eigen/unsupported/test/alignedvector3.cpp | 84 + .../Eigen/unsupported/test/autodiff.cpp | 371 + .../unsupported/test/autodiff_scalar.cpp | 101 + .../unsupported/test/cxx11_eventcount.cpp | 142 + .../Eigen/unsupported/test/cxx11_meta.cpp | 357 + .../test/cxx11_non_blocking_thread_pool.cpp | 107 + .../Eigen/unsupported/test/cxx11_runqueue.cpp | 235 + .../unsupported/test/cxx11_tensor_argmax.cpp | 294 + .../test/cxx11_tensor_argmax_cuda.cu | 251 + .../unsupported/test/cxx11_tensor_assign.cpp | 370 + .../test/cxx11_tensor_broadcast_sycl.cpp | 74 + .../test/cxx11_tensor_broadcasting.cpp | 194 + .../test/cxx11_tensor_cast_float16_cuda.cu | 79 + .../unsupported/test/cxx11_tensor_casts.cpp | 115 + .../test/cxx11_tensor_chipping.cpp | 425 + .../test/cxx11_tensor_comparisons.cpp | 84 + .../test/cxx11_tensor_complex_cuda.cu | 150 + .../cxx11_tensor_complex_cwise_ops_cuda.cu | 94 + .../test/cxx11_tensor_concatenation.cpp | 137 + .../unsupported/test/cxx11_tensor_const.cpp | 62 + .../test/cxx11_tensor_contract_cuda.cu | 213 + .../test/cxx11_tensor_contraction.cpp | 545 + .../test/cxx11_tensor_convolution.cpp | 149 + .../unsupported/test/cxx11_tensor_cuda.cu | 1284 ++ .../test/cxx11_tensor_custom_index.cpp | 100 + .../test/cxx11_tensor_custom_op.cpp | 111 + .../unsupported/test/cxx11_tensor_device.cu | 387 + .../test/cxx11_tensor_device_sycl.cpp | 31 + .../test/cxx11_tensor_dimension.cpp | 69 + .../unsupported/test/cxx11_tensor_empty.cpp | 40 + .../unsupported/test/cxx11_tensor_expr.cpp | 314 + .../unsupported/test/cxx11_tensor_fft.cpp | 273 + .../test/cxx11_tensor_fixed_size.cpp | 261 + .../test/cxx11_tensor_forced_eval.cpp | 79 + .../test/cxx11_tensor_forced_eval_sycl.cpp | 70 + .../test/cxx11_tensor_generator.cpp | 91 + .../unsupported/test/cxx11_tensor_ifft.cpp | 154 + .../test/cxx11_tensor_image_patch.cpp | 757 + .../test/cxx11_tensor_index_list.cpp | 386 + .../test/cxx11_tensor_inflation.cpp | 81 + .../unsupported/test/cxx11_tensor_intdiv.cpp | 147 + .../unsupported/test/cxx11_tensor_io.cpp | 136 + .../test/cxx11_tensor_layout_swap.cpp | 61 + .../unsupported/test/cxx11_tensor_lvalue.cpp | 42 + .../unsupported/test/cxx11_tensor_map.cpp | 277 + .../unsupported/test/cxx11_tensor_math.cpp | 46 + .../test/cxx11_tensor_mixed_indices.cpp | 53 + .../test/cxx11_tensor_morphing.cpp | 485 + .../test/cxx11_tensor_notification.cpp | 81 + .../test/cxx11_tensor_of_complex.cpp | 103 + .../test/cxx11_tensor_of_const_values.cpp | 105 + .../test/cxx11_tensor_of_float16_cuda.cu | 491 + .../test/cxx11_tensor_of_strings.cpp | 152 + .../unsupported/test/cxx11_tensor_padding.cpp | 93 + .../unsupported/test/cxx11_tensor_patch.cpp | 172 + .../unsupported/test/cxx11_tensor_random.cpp | 78 + .../test/cxx11_tensor_random_cuda.cu | 85 + .../test/cxx11_tensor_reduction.cpp | 508 + .../test/cxx11_tensor_reduction_cuda.cu | 154 + .../test/cxx11_tensor_reduction_sycl.cpp | 138 + .../unsupported/test/cxx11_tensor_ref.cpp | 248 + .../unsupported/test/cxx11_tensor_reverse.cpp | 190 + .../test/cxx11_tensor_roundings.cpp | 62 + .../unsupported/test/cxx11_tensor_scan.cpp | 110 + .../test/cxx11_tensor_scan_cuda.cu | 76 + .../test/cxx11_tensor_shuffling.cpp | 228 + .../unsupported/test/cxx11_tensor_simple.cpp | 327 + .../test/cxx11_tensor_striding.cpp | 119 + .../unsupported/test/cxx11_tensor_sugar.cpp | 81 + .../unsupported/test/cxx11_tensor_sycl.cpp | 159 + .../test/cxx11_tensor_symmetry.cpp | 818 + .../test/cxx11_tensor_thread_pool.cpp | 373 + .../unsupported/test/cxx11_tensor_uint128.cpp | 160 + .../test/cxx11_tensor_volume_patch.cpp | 112 + .../Eigen/unsupported/test/dgmres.cpp | 31 + .../Eigen/unsupported/test/forward_adolc.cpp | 141 + .../Eigen/unsupported/test/gmres.cpp | 31 + .../unsupported/test/kronecker_product.cpp | 252 + .../unsupported/test/levenberg_marquardt.cpp | 1477 ++ .../unsupported/test/matrix_exponential.cpp | 141 + .../unsupported/test/matrix_function.cpp | 193 + .../Eigen/unsupported/test/matrix_functions.h | 67 + .../Eigen/unsupported/test/matrix_power.cpp | 204 + .../unsupported/test/matrix_square_root.cpp | 31 + .../Eigen/unsupported/test/minres.cpp | 44 + .../Eigen/unsupported/test/mpreal/mpreal.h | 3104 +++ .../Eigen/unsupported/test/mpreal_support.cpp | 65 + .../Eigen/unsupported/test/openglsupport.cpp | 337 + .../unsupported/test/polynomialsolver.cpp | 218 + .../unsupported/test/polynomialutils.cpp | 113 + .../Eigen/unsupported/test/sparse_extra.cpp | 147 + .../unsupported/test/special_functions.cpp | 345 + .../Eigen/unsupported/test/splines.cpp | 281 + splinter/unsupported/Eigen/SVD | 39 - .../Eigen/src/IterativeSolvers/GMRES.h | 371 - .../src/IterativeSolvers/IncompleteCholesky.h | 278 - .../src/MatrixFunctions/MatrixExponential.h | 451 - .../src/MatrixFunctions/MatrixFunction.h | 591 - .../MatrixFunctions/MatrixFunctionAtomic.h | 131 - .../src/MatrixFunctions/MatrixLogarithm.h | 486 - .../src/MatrixFunctions/MatrixSquareRoot.h | 466 - .../Eigen/src/MatrixFunctions/StemFunction.h | 105 - splinter/unsupported/Eigen/src/SVD/BDCSVD.h | 748 - .../unsupported/Eigen/src/SVD/TODOBdcsvd.txt | 29 - .../Eigen/src/SVD/doneInBDCSVD.txt | 21 - .../Eigen/src/Splines/SplineFitting.h | 156 - splinter/utilities.cpp | 83 - splinter/utilities.h | 42 - splinter/version | 1 + ssc/CMakeLists.txt | 2 +- ssc/core.h | 4 - tcs/CMakeLists.txt | 2 +- tcs/csp_solver_cavity_receiver.cpp | 14 +- tcs/csp_solver_cavity_receiver.h | 14 +- test/CMakeLists.txt | 7 +- test/input_cases/ortools/NormHeatLoad.csv | 8760 ++++++++ .../ortools/constantNormHeatLoad.csv | 8760 ++++++++ .../ortools/generic_low_carbon_duck_curve.csv | 8760 ++++++++ test/input_cases/ortools/heat_load.csv | 8760 ++++++++ test/input_cases/ortools/heat_load_10x.csv | 8760 ++++++++ test/input_cases/ortools/heat_load_20x.csv | 8760 ++++++++ test/input_cases/ortools/heat_load_2x.csv | 8760 ++++++++ .../input_cases/ortools/heat_load_4x_peak.csv | 8760 ++++++++ test/input_cases/ortools/heat_load_5x.csv | 8760 ++++++++ test/main.cpp | 2 +- test/shared_test/lib_ortools_test.cpp | 139 + 787 files changed, 244863 insertions(+), 41292 deletions(-) create mode 100644 shared/lib_ortools.cpp create mode 100644 shared/lib_ortools.h create mode 100644 shared/lib_ptes_chp_dispatch.cpp create mode 100644 shared/lib_ptes_chp_dispatch.h delete mode 100644 splinter/Geometry delete mode 100644 splinter/SVD delete mode 100644 splinter/bspline.cpp delete mode 100644 splinter/bspline.h delete mode 100644 splinter/bsplinebasis.cpp delete mode 100644 splinter/bsplinebasis.h delete mode 100644 splinter/bsplinebasis1d.cpp delete mode 100644 splinter/bsplinebasis1d.h delete mode 100644 splinter/bsplinebuilder.cpp delete mode 100644 splinter/bsplinebuilder.h delete mode 100644 splinter/datapoint.cpp delete mode 100644 splinter/datapoint.h delete mode 100644 splinter/datatable.cpp delete mode 100644 splinter/datatable.h delete mode 100644 splinter/function.cpp delete mode 100644 splinter/function.h create mode 100644 splinter/include/bspline.h create mode 100644 splinter/include/bspline_basis.h create mode 100644 splinter/include/bspline_basis_1d.h create mode 100644 splinter/include/bspline_builders.h create mode 100644 splinter/include/bspline_utils.h create mode 100644 splinter/include/cinterface/cinterface.h create mode 100644 splinter/include/cinterface/utilities.h create mode 100644 splinter/include/data_point.h create mode 100644 splinter/include/data_table.h rename splinter/{ => include}/definitions.h (71%) create mode 100644 splinter/include/function.h create mode 100644 splinter/include/json.h create mode 100644 splinter/include/json_parser.h create mode 100644 splinter/include/knot_builders.h create mode 100644 splinter/include/knot_vector.h rename splinter/{mykroneckerproduct.h => include/kronecker_product.h} (52%) rename splinter/{linearsolvers.h => include/linear_solvers.h} (64%) create mode 100644 splinter/include/utilities.h delete mode 100644 splinter/knots.cpp delete mode 100644 splinter/knots.h delete mode 100644 splinter/saveable.h delete mode 100644 splinter/serializer.cpp delete mode 100644 splinter/serializer.h delete mode 100644 splinter/src/Core/Assign.h delete mode 100644 splinter/src/Core/Assign_MKL.h delete mode 100644 splinter/src/Core/CoreIterators.h delete mode 100644 splinter/src/Core/DenseStorage.h delete mode 100644 splinter/src/Core/DiagonalProduct.h delete mode 100644 splinter/src/Core/Flagged.h delete mode 100644 splinter/src/Core/Functors.h delete mode 100644 splinter/src/Core/GeneralProduct.h delete mode 100644 splinter/src/Core/GenericPacketMath.h delete mode 100644 splinter/src/Core/GlobalFunctions.h delete mode 100644 splinter/src/Core/MathFunctions.h delete mode 100644 splinter/src/Core/ProductBase.h delete mode 100644 splinter/src/Core/Reverse.h delete mode 100644 splinter/src/Core/SelfAdjointView.h delete mode 100644 splinter/src/Core/SelfCwiseBinaryOp.h delete mode 100644 splinter/src/Core/Swap.h delete mode 100644 splinter/src/Core/TriangularMatrix.h delete mode 100644 splinter/src/Core/arch/AltiVec/Complex.h delete mode 100644 splinter/src/Core/arch/AltiVec/PacketMath.h delete mode 100644 splinter/src/Core/arch/NEON/Complex.h delete mode 100644 splinter/src/Core/arch/NEON/PacketMath.h delete mode 100644 splinter/src/Core/products/CoeffBasedProduct.h delete mode 100644 splinter/src/Core/products/GeneralBlockPanelKernel.h delete mode 100644 splinter/src/Core/products/GeneralMatrixMatrix.h delete mode 100644 splinter/src/Core/util/Meta.h delete mode 100644 splinter/src/Core/util/ReenableStupidWarnings.h delete mode 100644 splinter/src/Core/util/XprHelper.h delete mode 100644 splinter/src/Eigen2Support/Block.h delete mode 100644 splinter/src/Eigen2Support/Cwise.h delete mode 100644 splinter/src/Eigen2Support/CwiseOperators.h delete mode 100644 splinter/src/Eigen2Support/Geometry/AlignedBox.h delete mode 100644 splinter/src/Eigen2Support/Geometry/All.h delete mode 100644 splinter/src/Eigen2Support/Geometry/AngleAxis.h delete mode 100644 splinter/src/Eigen2Support/Geometry/Hyperplane.h delete mode 100644 splinter/src/Eigen2Support/Geometry/ParametrizedLine.h delete mode 100644 splinter/src/Eigen2Support/Geometry/Quaternion.h delete mode 100644 splinter/src/Eigen2Support/Geometry/Rotation2D.h delete mode 100644 splinter/src/Eigen2Support/Geometry/RotationBase.h delete mode 100644 splinter/src/Eigen2Support/Geometry/Scaling.h delete mode 100644 splinter/src/Eigen2Support/Geometry/Transform.h delete mode 100644 splinter/src/Eigen2Support/Geometry/Translation.h delete mode 100644 splinter/src/Eigen2Support/LU.h delete mode 100644 splinter/src/Eigen2Support/Lazy.h delete mode 100644 splinter/src/Eigen2Support/LeastSquares.h delete mode 100644 splinter/src/Eigen2Support/Macros.h delete mode 100644 splinter/src/Eigen2Support/MathFunctions.h delete mode 100644 splinter/src/Eigen2Support/Memory.h delete mode 100644 splinter/src/Eigen2Support/Meta.h delete mode 100644 splinter/src/Eigen2Support/Minor.h delete mode 100644 splinter/src/Eigen2Support/QR.h delete mode 100644 splinter/src/Eigen2Support/SVD.h delete mode 100644 splinter/src/Eigen2Support/TriangularSolver.h delete mode 100644 splinter/src/Eigen2Support/VectorBlock.h delete mode 100644 splinter/src/Geometry/Homogeneous.h delete mode 100644 splinter/src/Householder/BlockHouseholder.h delete mode 100644 splinter/src/IterativeLinearSolvers/IterativeSolverBase.h delete mode 100644 splinter/src/SVD/JacobiSVD.h delete mode 100644 splinter/src/SVD/UpperBidiagonalization.h delete mode 100644 splinter/src/SparseCore/ConservativeSparseSparseProduct.h delete mode 100644 splinter/src/SparseCore/MappedSparseMatrix.h delete mode 100644 splinter/src/SparseCore/SparseBlock.h delete mode 100644 splinter/src/SparseCore/SparseCwiseBinaryOp.h delete mode 100644 splinter/src/SparseCore/SparseCwiseUnaryOp.h delete mode 100644 splinter/src/SparseCore/SparseDenseProduct.h delete mode 100644 splinter/src/SparseCore/SparseDiagonalProduct.h delete mode 100644 splinter/src/SparseCore/SparseFuzzy.h delete mode 100644 splinter/src/SparseCore/SparsePermutation.h delete mode 100644 splinter/src/SparseCore/SparseProduct.h delete mode 100644 splinter/src/SparseCore/SparseSelfAdjointView.h delete mode 100644 splinter/src/SparseCore/SparseTranspose.h delete mode 100644 splinter/src/SparseCore/SparseTriangularView.h delete mode 100644 splinter/src/SparseCore/SparseView.h create mode 100644 splinter/src/bspline.cpp create mode 100644 splinter/src/bspline_basis.cpp create mode 100644 splinter/src/bspline_basis_1d.cpp create mode 100644 splinter/src/bspline_builders.cpp create mode 100644 splinter/src/bspline_utils.cpp create mode 100644 splinter/src/cinterface/bspline.cpp create mode 100644 splinter/src/cinterface/bspline_builders.cpp create mode 100644 splinter/src/cinterface/cinterface.cpp create mode 100644 splinter/src/cinterface/data_table.cpp create mode 100644 splinter/src/cinterface/utilities.cpp create mode 100644 splinter/src/data_point.cpp create mode 100644 splinter/src/data_table.cpp create mode 100644 splinter/src/function.cpp create mode 100644 splinter/src/json_parser.cpp create mode 100644 splinter/src/knot_builders.cpp create mode 100644 splinter/src/knot_vector.cpp rename splinter/{mykroneckerproduct.cpp => src/kronecker_product.cpp} (84%) delete mode 100644 splinter/src/misc/Solve.h delete mode 100644 splinter/src/misc/SparseSolve.h delete mode 100644 splinter/src/misc/blas.h delete mode 100644 splinter/src/plugins/ArrayCwiseBinaryOps.h delete mode 100644 splinter/src/plugins/ArrayCwiseUnaryOps.h delete mode 100644 splinter/src/plugins/BlockMethods.h delete mode 100644 splinter/src/plugins/CommonCwiseBinaryOps.h delete mode 100644 splinter/src/plugins/CommonCwiseUnaryOps.h delete mode 100644 splinter/src/plugins/MatrixCwiseUnaryOps.h create mode 100644 splinter/src/utilities.cpp create mode 100644 splinter/thirdparty/Catch/Catch.h create mode 100644 splinter/thirdparty/Eigen/Eigen/CMakeLists.txt rename splinter/{ => thirdparty/Eigen/Eigen}/Cholesky (50%) create mode 100644 splinter/thirdparty/Eigen/Eigen/CholmodSupport rename splinter/{ => thirdparty/Eigen/Eigen}/Core (56%) create mode 100644 splinter/thirdparty/Eigen/Eigen/Dense create mode 100644 splinter/thirdparty/Eigen/Eigen/Eigen rename splinter/{ => thirdparty/Eigen/Eigen}/Eigenvalues (68%) create mode 100644 splinter/thirdparty/Eigen/Eigen/Geometry rename splinter/{ => thirdparty/Eigen/Eigen}/Householder (66%) rename splinter/{ => thirdparty/Eigen/Eigen}/IterativeLinearSolvers (63%) rename splinter/{ => thirdparty/Eigen/Eigen}/Jacobi (68%) rename splinter/{ => thirdparty/Eigen/Eigen}/LU (55%) create mode 100644 splinter/thirdparty/Eigen/Eigen/MetisSupport rename splinter/{ => thirdparty/Eigen/Eigen}/OrderingMethods (88%) create mode 100644 splinter/thirdparty/Eigen/Eigen/PaStiXSupport create mode 100755 splinter/thirdparty/Eigen/Eigen/PardisoSupport rename splinter/{ => thirdparty/Eigen/Eigen}/QR (51%) create mode 100644 splinter/thirdparty/Eigen/Eigen/QtAlignedMalloc create mode 100644 splinter/thirdparty/Eigen/Eigen/SPQRSupport create mode 100644 splinter/thirdparty/Eigen/Eigen/SVD create mode 100644 splinter/thirdparty/Eigen/Eigen/Sparse rename splinter/{ => thirdparty/Eigen/Eigen}/SparseCholesky (95%) rename splinter/{ => thirdparty/Eigen/Eigen}/SparseCore (77%) rename splinter/{ => thirdparty/Eigen/Eigen}/SparseLU (96%) rename splinter/{ => thirdparty/Eigen/Eigen}/SparseQR (76%) create mode 100644 splinter/thirdparty/Eigen/Eigen/StdDeque create mode 100644 splinter/thirdparty/Eigen/Eigen/StdList create mode 100644 splinter/thirdparty/Eigen/Eigen/StdVector create mode 100644 splinter/thirdparty/Eigen/Eigen/SuperLUSupport create mode 100644 splinter/thirdparty/Eigen/Eigen/UmfPackSupport rename splinter/{ => thirdparty/Eigen/Eigen}/src/Cholesky/LDLT.h (70%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Cholesky/LLT.h (70%) rename splinter/{src/Cholesky/LLT_MKL.h => thirdparty/Eigen/Eigen/src/Cholesky/LLT_LAPACKE.h} (71%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/CholmodSupport/CholmodSupport.h (68%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/Array.h (79%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/ArrayBase.h (75%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/ArrayWrapper.h (58%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/Assign.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/AssignEvaluator.h create mode 100755 splinter/thirdparty/Eigen/Eigen/src/Core/Assign_MKL.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/BandMatrix.h (83%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/Block.h (61%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/BooleanRedux.h (69%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/CommaInitializer.h (81%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/ConditionEstimator.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/CoreEvaluators.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/CoreIterators.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/CwiseBinaryOp.h (50%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/CwiseNullaryOp.h (67%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/CwiseTernaryOp.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/CwiseUnaryOp.h (50%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/CwiseUnaryView.h (70%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/DenseBase.h (56%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/DenseCoeffsBase.h (72%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/DenseStorage.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/Diagonal.h (78%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/DiagonalMatrix.h (71%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/DiagonalProduct.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/Dot.h (54%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/EigenBase.h (74%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/ForceAlignedAccess.h (79%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/Fuzzy.h (94%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/GeneralProduct.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/GenericPacketMath.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/GlobalFunctions.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/IO.h (85%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/Inverse.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/Map.h (62%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/MapBase.h (66%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/MathFunctions.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/MathFunctionsImpl.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/Matrix.h (71%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/MatrixBase.h (64%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/NestByValue.h (72%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/NoAlias.h (52%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/NumTraits.h (56%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/PermutationMatrix.h (60%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/PlainObjectBase.h (67%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/Product.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/ProductEvaluators.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/Random.h (68%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/Redux.h (60%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/Ref.h (69%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/Replicate.h (66%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/ReturnByValue.h (69%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/Reverse.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/Select.h (88%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/SelfAdjointView.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/SelfCwiseBinaryOp.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/Solve.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/SolveTriangular.h (70%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/SolverBase.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/StableNorm.h (78%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/Stride.h (80%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/Swap.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/Transpose.h (75%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/Transpositions.h (64%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/TriangularMatrix.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/VectorBlock.h (94%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/VectorwiseOp.h (67%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/Visitor.h (74%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/AVX/Complex.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/AVX/MathFunctions.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/AVX/PacketMath.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/AVX/TypeCasting.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/AVX512/MathFunctions.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/AVX512/PacketMath.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/AltiVec/Complex.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/AltiVec/MathFunctions.h create mode 100755 splinter/thirdparty/Eigen/Eigen/src/Core/arch/AltiVec/PacketMath.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/CUDA/Complex.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/CUDA/Half.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/CUDA/MathFunctions.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/CUDA/PacketMath.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/CUDA/PacketMathHalf.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/CUDA/TypeCasting.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/Default/ConjHelper.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/arch/Default/Settings.h (100%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/NEON/Complex.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/NEON/MathFunctions.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/NEON/PacketMath.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/arch/SSE/Complex.h (81%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/arch/SSE/MathFunctions.h (78%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/arch/SSE/PacketMath.h (59%) mode change 100644 => 100755 create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/SSE/TypeCasting.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/ZVector/Complex.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/arch/ZVector/MathFunctions.h create mode 100755 splinter/thirdparty/Eigen/Eigen/src/Core/arch/ZVector/PacketMath.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/functors/AssignmentFunctors.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/functors/BinaryFunctors.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/functors/NullaryFunctors.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/functors/StlFunctors.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/functors/TernaryFunctors.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/functors/UnaryFunctors.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/products/GeneralBlockPanelKernel.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/products/GeneralMatrixMatrix.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/products/GeneralMatrixMatrixTriangular.h (65%) rename splinter/{src/Core/products/GeneralMatrixMatrixTriangular_MKL.h => thirdparty/Eigen/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h} (67%) rename splinter/{src/Core/products/GeneralMatrixMatrix_MKL.h => thirdparty/Eigen/Eigen/src/Core/products/GeneralMatrixMatrix_BLAS.h} (72%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/products/GeneralMatrixVector.h (55%) rename splinter/{src/Core/products/GeneralMatrixVector_MKL.h => thirdparty/Eigen/Eigen/src/Core/products/GeneralMatrixVector_BLAS.h} (57%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/products/Parallelizer.h (65%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/products/SelfadjointMatrixMatrix.h (51%) rename splinter/{src/Core/products/SelfadjointMatrixMatrix_MKL.h => thirdparty/Eigen/Eigen/src/Core/products/SelfadjointMatrixMatrix_BLAS.h} (65%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/products/SelfadjointMatrixVector.h (65%) rename splinter/{src/Core/products/SelfadjointMatrixVector_MKL.h => thirdparty/Eigen/Eigen/src/Core/products/SelfadjointMatrixVector_BLAS.h} (70%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/products/SelfadjointProduct.h (85%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/products/SelfadjointRank2Update.h (89%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/products/TriangularMatrixMatrix.h (70%) rename splinter/{src/Core/products/TriangularMatrixMatrix_MKL.h => thirdparty/Eigen/Eigen/src/Core/products/TriangularMatrixMatrix_BLAS.h} (73%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/products/TriangularMatrixVector.h (63%) rename splinter/{src/Core/products/TriangularMatrixVector_MKL.h => thirdparty/Eigen/Eigen/src/Core/products/TriangularMatrixVector_BLAS.h} (69%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/products/TriangularSolverMatrix.h (81%) rename splinter/{src/Core/products/TriangularSolverMatrix_MKL.h => thirdparty/Eigen/Eigen/src/Core/products/TriangularSolverMatrix_BLAS.h} (70%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/products/TriangularSolverVector.h (86%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/util/BlasUtil.h (51%) mode change 100644 => 100755 rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/util/Constants.h (75%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/util/DisableStupidWarnings.h (56%) mode change 100644 => 100755 rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/util/ForwardDeclarations.h (75%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/util/MKL_support.h (73%) mode change 100644 => 100755 rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/util/Macros.h (51%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/util/Memory.h (68%) create mode 100755 splinter/thirdparty/Eigen/Eigen/src/Core/util/Meta.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/util/NonMPL2.h (100%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/util/ReenableStupidWarnings.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Core/util/StaticAssert.h (60%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Core/util/XprHelper.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Eigenvalues/ComplexEigenSolver.h (92%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Eigenvalues/ComplexSchur.h (96%) rename splinter/{src/Eigenvalues/ComplexSchur_MKL.h => thirdparty/Eigen/Eigen/src/Eigenvalues/ComplexSchur_LAPACKE.h} (65%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Eigenvalues/EigenSolver.h (86%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Eigenvalues/GeneralizedEigenSolver.h (64%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h (99%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Eigenvalues/HessenbergDecomposition.h (97%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Eigenvalues/MatrixBaseEigenvalues.h (100%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Eigenvalues/RealQZ.h (93%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Eigenvalues/RealSchur.h (94%) rename splinter/{src/Eigenvalues/RealSchur_MKL.h => thirdparty/Eigen/Eigen/src/Eigenvalues/RealSchur_LAPACKE.h} (64%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Eigenvalues/SelfAdjointEigenSolver.h (78%) rename splinter/{src/Eigenvalues/SelfAdjointEigenSolver_MKL.h => thirdparty/Eigen/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h} (65%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Eigenvalues/Tridiagonalization.h (95%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Geometry/AlignedBox.h (73%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Geometry/AngleAxis.h (69%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Geometry/EulerAngles.h (88%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Geometry/Homogeneous.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Geometry/Hyperplane.h (75%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Geometry/OrthoMethods.h (77%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Geometry/ParametrizedLine.h (64%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Geometry/Quaternion.h (70%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Geometry/Rotation2D.h (57%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Geometry/RotationBase.h (70%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Geometry/Scaling.h (84%) mode change 100644 => 100755 rename splinter/{ => thirdparty/Eigen/Eigen}/src/Geometry/Transform.h (83%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Geometry/Translation.h (67%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Geometry/Umeyama.h (89%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Geometry/arch/Geometry_SSE.h (50%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/Householder/BlockHouseholder.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Householder/Householder.h (96%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/Householder/HouseholderSequence.h (89%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/IterativeLinearSolvers/BasicPreconditioners.h (50%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/IterativeLinearSolvers/BiCGSTAB.h (73%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/IterativeLinearSolvers/ConjugateGradient.h (60%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/IterativeLinearSolvers/IncompleteCholesky.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/IterativeLinearSolvers/IncompleteLUT.h (79%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/IterativeLinearSolvers/LeastSquareConjugateGradient.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/Jacobi/Jacobi.h (65%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/LU/Determinant.h (97%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/LU/FullPivLU.h (75%) rename splinter/{src/LU/Inverse.h => thirdparty/Eigen/Eigen/src/LU/InverseImpl.h} (86%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/LU/PartialPivLU.h (69%) rename splinter/{src/LU/PartialPivLU_MKL.h => thirdparty/Eigen/Eigen/src/LU/PartialPivLU_LAPACKE.h} (77%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/LU/arch/Inverse_SSE.h (83%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/MetisSupport/MetisSupport.h (87%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/OrderingMethods/Amd.h (84%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/OrderingMethods/Eigen_Colamd.h (79%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/OrderingMethods/Ordering.h (69%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/PaStiXSupport/PaStiXSupport.h (81%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/PardisoSupport/PardisoSupport.h (68%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/QR/ColPivHouseholderQR.h (72%) rename splinter/{src/QR/ColPivHouseholderQR_MKL.h => thirdparty/Eigen/Eigen/src/QR/ColPivHouseholderQR_LAPACKE.h} (64%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/QR/CompleteOrthogonalDecomposition.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/QR/FullPivHouseholderQR.h (80%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/QR/HouseholderQR.h (81%) rename splinter/{src/QR/HouseholderQR_MKL.h => thirdparty/Eigen/Eigen/src/QR/HouseholderQR_LAPACKE.h} (77%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SPQRSupport/SuiteSparseQRSupport.h (74%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SVD/BDCSVD.h rename splinter/{unsupported => thirdparty/Eigen}/Eigen/src/SVD/JacobiSVD.h (72%) rename splinter/{src/SVD/JacobiSVD_MKL.h => thirdparty/Eigen/Eigen/src/SVD/JacobiSVD_LAPACKE.h} (60%) rename splinter/{unsupported => thirdparty/Eigen}/Eigen/src/SVD/SVDBase.h (52%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SVD/UpperBidiagonalization.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseCholesky/SimplicialCholesky.h (74%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseCholesky/SimplicialCholesky_impl.h (86%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseCore/AmbiVector.h (76%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseCore/CompressedStorage.h (51%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/MappedSparseMatrix.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparseAssign.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparseBlock.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseCore/SparseColEtree.h (82%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparseCompressedBase.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparseCwiseBinaryOp.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparseCwiseUnaryOp.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparseDenseProduct.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparseDiagonalProduct.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseCore/SparseDot.h (85%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparseFuzzy.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparseMap.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseCore/SparseMatrix.h (63%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseCore/SparseMatrixBase.h (65%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparsePermutation.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparseProduct.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseCore/SparseRedux.h (74%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparseRef.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparseSelfAdjointView.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparseSolverBase.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseCore/SparseSparseProductWithPruning.h (60%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparseTranspose.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparseTriangularView.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseCore/SparseUtil.h (53%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseCore/SparseVector.h (67%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/SparseCore/SparseView.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseCore/TriangularSolver.h (71%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLU.h (81%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLUImpl.h (92%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLU_Memory.h (92%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLU_Structs.h (98%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLU_SupernodalMatrix.h (78%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLU_Utils.h (83%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLU_column_bmod.h (94%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLU_column_dfs.h (78%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLU_copy_to_ucol.h (90%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLU_gemm_kernel.h (75%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLU_heap_relax_snode.h (86%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLU_kernel_bmod.h (70%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLU_panel_bmod.h (97%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLU_panel_dfs.h (84%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLU_pivotL.h (90%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLU_pruneL.h (91%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseLU/SparseLU_relax_snode.h (87%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SparseQR/SparseQR.h (80%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/StlSupport/StdDeque.h (96%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/StlSupport/StdList.h (94%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/StlSupport/StdVector.h (97%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/StlSupport/details.h (89%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/SuperLUSupport/SuperLUSupport.h (81%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/UmfPackSupport/UmfPackSupport.h (65%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/misc/Image.h (97%) rename splinter/{ => thirdparty/Eigen/Eigen}/src/misc/Kernel.h (95%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/misc/RealSvd2x2.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/misc/blas.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/misc/lapack.h create mode 100755 splinter/thirdparty/Eigen/Eigen/src/misc/lapacke.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/misc/lapacke_mangling.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/plugins/ArrayCwiseBinaryOps.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/plugins/ArrayCwiseUnaryOps.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/plugins/BlockMethods.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/plugins/CommonCwiseBinaryOps.h create mode 100644 splinter/thirdparty/Eigen/Eigen/src/plugins/CommonCwiseUnaryOps.h rename splinter/{ => thirdparty/Eigen/Eigen}/src/plugins/MatrixCwiseBinaryOps.h (83%) create mode 100644 splinter/thirdparty/Eigen/Eigen/src/plugins/MatrixCwiseUnaryOps.h create mode 100644 splinter/thirdparty/Eigen/unsupported/CMakeLists.txt rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/AdolcForward (99%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/AlignedVector3 (83%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/ArpackSupport (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/AutoDiff (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/BVH (100%) create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CMakeLists.txt create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/CMakeLists.txt create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/Tensor create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/TensorSymmetry create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/ThreadPool create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/README.md create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/Tensor.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorArgMax.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorAssign.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorBase.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorBroadcasting.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorChipping.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorConcatenation.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionBlocking.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionCuda.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionMapper.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionThreadPool.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorConversion.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorConvolution.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorCostModel.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorCustomOp.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDevice.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceCuda.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceDefault.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceSycl.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceThreadPool.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDimensionList.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDimensions.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorEvalTo.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorEvaluator.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorExecutor.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorExpr.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorFFT.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorFixedSize.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorForcedEval.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorForwardDeclarations.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorFunctors.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorGenerator.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorGlobalFunctions.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorIO.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorImagePatch.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorIndexList.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorInflation.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorInitializer.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorIntDiv.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorLayoutSwap.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMacros.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMap.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMeta.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMorphing.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorPadding.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorPatch.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorRandom.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorReduction.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorReductionCuda.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorReductionSycl.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorRef.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorReverse.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorScan.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorShuffling.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorStriding.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSycl.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSyclConvertToDeviceExpression.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSyclExprConstructor.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSyclExtractAccessor.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSyclExtractFunctors.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSyclLeafCount.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSyclPlaceHolderExpr.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSyclRun.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSyclTuple.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorTraits.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorUInt128.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/Tensor/TensorVolumePatch.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/TensorSymmetry/DynamicSymmetry.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/TensorSymmetry/StaticSymmetry.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/TensorSymmetry/Symmetry.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/TensorSymmetry/util/TemplateGroupTheory.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/ThreadPool/EventCount.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/ThreadPool/NonBlockingThreadPool.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/ThreadPool/RunQueue.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/ThreadPool/SimpleThreadPool.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/ThreadPool/ThreadEnvironment.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/ThreadPool/ThreadLocal.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/ThreadPool/ThreadPoolInterface.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/ThreadPool/ThreadYield.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/util/CXX11Meta.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/util/CXX11Workarounds.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/util/EmulateArray.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/util/EmulateCXX11Meta.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/CXX11/src/util/MaxSizeVector.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/EulerAngles rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/FFT (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/IterativeSolvers (89%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/KroneckerProduct (78%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/LevenbergMarquardt (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/MPRealSupport (58%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/MatrixFunctions (86%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/MoreVectorization (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/NonLinearOptimization (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/NumericalDiff (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/OpenGLSupport (96%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/Polynomials (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/Skyline (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/SparseExtra (93%) create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/SpecialFunctions rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/Splines (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/AutoDiff/AutoDiffJacobian.h (61%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h (68%) mode change 100644 => 100755 rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/AutoDiff/AutoDiffVector.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/BVH/BVAlgorithms.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/BVH/KdBVH.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/Eigenvalues/ArpackSelfAdjointEigenSolver.h (99%) create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/EulerAngles/CMakeLists.txt create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/EulerAngles/EulerAngles.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/EulerAngles/EulerSystem.h rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/FFT/ei_fftw_impl.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/FFT/ei_kissfft_impl.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/IterativeSolvers/ConstrainedConjGrad.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/IterativeSolvers/DGMRES.h (81%) create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/IterativeSolvers/GMRES.h rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/IterativeSolvers/IncompleteLU.h (68%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/IterativeSolvers/IterationController.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/IterativeSolvers/MINRES.h (82%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/IterativeSolvers/Scaling.h (99%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h (60%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/LevenbergMarquardt/CopyrightMINPACK.txt (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/LevenbergMarquardt/LMcovar.h (98%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/LevenbergMarquardt/LMonestep.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/LevenbergMarquardt/LMpar.h (98%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/LevenbergMarquardt/LMqrsolv.h (97%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/LevenbergMarquardt/LevenbergMarquardt.h (92%) create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/MatrixFunctions/MatrixLogarithm.h rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/MatrixFunctions/MatrixPower.h (53%) create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/MatrixFunctions/MatrixSquareRoot.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/MatrixFunctions/StemFunction.h rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/MoreVectorization/MathFunctions.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h (99%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h (97%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/NonLinearOptimization/chkder.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/NonLinearOptimization/covar.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/NonLinearOptimization/dogleg.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/NonLinearOptimization/lmpar.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/NonLinearOptimization/r1mpyq.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/NonLinearOptimization/r1updt.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/Polynomials/Companion.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/Polynomials/PolynomialSolver.h (94%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/Polynomials/PolynomialUtils.h (98%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/Skyline/SkylineInplaceLU.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/Skyline/SkylineMatrix.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/Skyline/SkylineMatrixBase.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/Skyline/SkylineProduct.h (97%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/Skyline/SkylineStorage.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/Skyline/SkylineUtil.h (100%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/SparseExtra/BlockOfDynamicSparseMatrix.h (100%) create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/SparseExtra/BlockSparseMatrix.h rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h (80%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/SparseExtra/MarketIO.h (91%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/SparseExtra/MatrixMarketIterator.h (83%) rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/SparseExtra/RandomSetter.h (96%) create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsArrayAPI.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsFunctors.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsHalf.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsImpl.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsPacketMath.h create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/SpecialFunctions/arch/CUDA/CudaSpecialFunctions.h rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/Splines/Spline.h (85%) create mode 100644 splinter/thirdparty/Eigen/unsupported/Eigen/src/Splines/SplineFitting.h rename splinter/{ => thirdparty/Eigen}/unsupported/Eigen/src/Splines/SplineFwd.h (85%) create mode 100644 splinter/thirdparty/Eigen/unsupported/README.txt rename splinter/{ => thirdparty/Eigen}/unsupported/bench/bench_svd.cpp (100%) create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/CMakeLists.txt create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/Overview.dox create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/eigendoxy_layout.xml.in create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/examples/BVH_Example.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/examples/CMakeLists.txt create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/examples/EulerAngles.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/examples/FFT.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/examples/MatrixExponential.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/examples/MatrixFunction.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/examples/MatrixLogarithm.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/examples/MatrixPower.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/examples/MatrixPower_optimal.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/examples/MatrixSine.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/examples/MatrixSinh.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/examples/MatrixSquareRoot.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/examples/PolynomialSolver1.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/examples/PolynomialUtils1.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/doc/snippets/CMakeLists.txt create mode 100644 splinter/thirdparty/Eigen/unsupported/test/BVH.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/CMakeLists.txt create mode 100644 splinter/thirdparty/Eigen/unsupported/test/EulerAngles.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/FFT.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/FFTW.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/NonLinearOptimization.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/NumericalDiff.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/alignedvector3.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/autodiff.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/autodiff_scalar.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_eventcount.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_meta.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_non_blocking_thread_pool.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_runqueue.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_argmax.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_argmax_cuda.cu create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_assign.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_broadcast_sycl.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_broadcasting.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_cast_float16_cuda.cu create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_casts.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_chipping.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_comparisons.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_complex_cuda.cu create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_complex_cwise_ops_cuda.cu create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_concatenation.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_const.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_contract_cuda.cu create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_contraction.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_convolution.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_cuda.cu create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_custom_index.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_custom_op.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_device.cu create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_device_sycl.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_dimension.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_empty.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_expr.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_fft.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_fixed_size.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_forced_eval.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_forced_eval_sycl.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_generator.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_ifft.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_image_patch.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_index_list.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_inflation.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_intdiv.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_io.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_layout_swap.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_lvalue.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_map.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_math.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_mixed_indices.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_morphing.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_notification.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_of_complex.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_of_const_values.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_of_float16_cuda.cu create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_of_strings.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_padding.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_patch.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_random.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_random_cuda.cu create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_reduction.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_reduction_cuda.cu create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_reduction_sycl.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_ref.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_reverse.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_roundings.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_scan.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_scan_cuda.cu create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_shuffling.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_simple.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_striding.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_sugar.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_sycl.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_symmetry.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_thread_pool.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_uint128.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/cxx11_tensor_volume_patch.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/dgmres.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/forward_adolc.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/gmres.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/kronecker_product.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/levenberg_marquardt.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/matrix_exponential.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/matrix_function.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/matrix_functions.h create mode 100644 splinter/thirdparty/Eigen/unsupported/test/matrix_power.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/matrix_square_root.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/minres.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/mpreal/mpreal.h create mode 100644 splinter/thirdparty/Eigen/unsupported/test/mpreal_support.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/openglsupport.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/polynomialsolver.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/polynomialutils.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/sparse_extra.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/special_functions.cpp create mode 100644 splinter/thirdparty/Eigen/unsupported/test/splines.cpp delete mode 100644 splinter/unsupported/Eigen/SVD delete mode 100644 splinter/unsupported/Eigen/src/IterativeSolvers/GMRES.h delete mode 100644 splinter/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h delete mode 100644 splinter/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h delete mode 100644 splinter/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h delete mode 100644 splinter/unsupported/Eigen/src/MatrixFunctions/MatrixFunctionAtomic.h delete mode 100644 splinter/unsupported/Eigen/src/MatrixFunctions/MatrixLogarithm.h delete mode 100644 splinter/unsupported/Eigen/src/MatrixFunctions/MatrixSquareRoot.h delete mode 100644 splinter/unsupported/Eigen/src/MatrixFunctions/StemFunction.h delete mode 100644 splinter/unsupported/Eigen/src/SVD/BDCSVD.h delete mode 100644 splinter/unsupported/Eigen/src/SVD/TODOBdcsvd.txt delete mode 100644 splinter/unsupported/Eigen/src/SVD/doneInBDCSVD.txt delete mode 100644 splinter/unsupported/Eigen/src/Splines/SplineFitting.h delete mode 100644 splinter/utilities.cpp delete mode 100644 splinter/utilities.h create mode 100644 splinter/version create mode 100644 test/input_cases/ortools/NormHeatLoad.csv create mode 100644 test/input_cases/ortools/constantNormHeatLoad.csv create mode 100644 test/input_cases/ortools/generic_low_carbon_duck_curve.csv create mode 100644 test/input_cases/ortools/heat_load.csv create mode 100644 test/input_cases/ortools/heat_load_10x.csv create mode 100644 test/input_cases/ortools/heat_load_20x.csv create mode 100644 test/input_cases/ortools/heat_load_2x.csv create mode 100644 test/input_cases/ortools/heat_load_4x_peak.csv create mode 100644 test/input_cases/ortools/heat_load_5x.csv create mode 100644 test/shared_test/lib_ortools_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ba4b02697..8e26e25f50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,10 +154,10 @@ endfunction() add_subdirectory(splinter) -if (NOT SKIP_ORTOOLS) - add_subdirectory(or-tools) - add_subdirectory(ortools_sandbox) -endif() +add_subdirectory(shared) +add_subdirectory(nlopt) +add_subdirectory(lpsolve) +add_subdirectory(solarpilot) add_subdirectory(tcs) add_subdirectory(ssc) diff --git a/shared/CMakeLists.txt b/shared/CMakeLists.txt index d9ad0051db..6025fb9417 100644 --- a/shared/CMakeLists.txt +++ b/shared/CMakeLists.txt @@ -5,7 +5,7 @@ ##################################################################################################################### set(CMAKE_VERBOSE_MAKEFILE ON) -include_directories(. ../splinter) +include_directories(. ../splinter/include ../splinter/thirdparty/Eigen ../) set(SHARED_SRC 6par_gamma.h @@ -69,6 +69,8 @@ set(SHARED_SRC lib_power_electronics.h lib_powerblock.cpp lib_powerblock.h + lib_ptes_chp_dispatch.cpp + lib_ptes_chp_dispatch.h lib_pv_incidence_modifier.cpp lib_pv_incidence_modifier.h lib_pv_io_manager.cpp @@ -143,6 +145,11 @@ set( DEPENDENCIES splinter ) +find_package(re2 CONFIG REQUIRED) +find_package(Eigen3 CONFIG REQUIRED) +find_package(ortools CONFIG REQUIRED) +target_link_libraries(shared ortools::ortools) + if (UNIX) set(CMAKE_SHARED_LINKER_FLAGS "-lm") endif () diff --git a/shared/lib_mlmodel.cpp b/shared/lib_mlmodel.cpp index 6df193d016..151ae1f8cf 100644 --- a/shared/lib_mlmodel.cpp +++ b/shared/lib_mlmodel.cpp @@ -44,11 +44,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include "lib_mlmodel.h" // #include "mlm_spline.h" -#include "bsplinebuilder.h" -#include "datatable.h" +#include +#include static const double k = 1.38064852e-23; // Boltzmann constant [J/K] static const double q = 1.60217662e-19; // Elemenatry charge [C] @@ -74,7 +75,6 @@ static const int AM_MODE_LEE_PANCHULA = 4; mlmodel_module_t::mlmodel_module_t() { - m_bspline3 = BSpline(1); Width = Length = V_mp_ref = I_mp_ref = V_oc_ref = I_sc_ref = S_ref = T_ref = R_shref = R_sh0 = R_shexp = R_s = alpha_isc = beta_voc_spec = E_g = n_0 = mu_n = D2MuTau = T_c_no_tnoct @@ -131,9 +131,9 @@ void mlmodel_module_t::initializeManual() */ DataTable samples; for (int i = 0; i <= IAM_c_cs_elements - 1; i = i + 1) { - samples.addSample(IAM_c_cs_incAngle[i], IAM_c_cs_iamValue[i]); + samples.add_sample(IAM_c_cs_incAngle[i], IAM_c_cs_iamValue[i]); } - m_bspline3 = BSpline::Builder(samples).degree(3).build(); + m_bspline3 = std::make_unique(bspline_interpolator(samples, 3)); isInitialized = true; } @@ -170,11 +170,11 @@ bool mlmodel_module_t::operator() (pvinput_t &input, double T_C, double opvoltag // f_IAM_gnd = std::min(iamSpline(theta_gnd), 1.0); DenseVector x(1); x(0) = theta_beam; - f_IAM_beam = std::min(m_bspline3.eval(x), 1.0); + f_IAM_beam = std::min((*m_bspline3).eval(x)[0], 1.0); x(0) = theta_diff; - f_IAM_diff = std::min(m_bspline3.eval(x), 1.0); + f_IAM_diff = std::min((*m_bspline3).eval(x)[0], 1.0); x(0) = theta_gnd; - f_IAM_gnd = std::min(m_bspline3.eval(x), 1.0); + f_IAM_gnd = std::min((*m_bspline3).eval(x)[0], 1.0); break; } diff --git a/shared/lib_mlmodel.h b/shared/lib_mlmodel.h index f1e8eb9d1e..f7b6edb574 100644 --- a/shared/lib_mlmodel.h +++ b/shared/lib_mlmodel.h @@ -34,7 +34,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef __mlmodel_h #define __mlmodel_h - +#include #include "lib_pvmodel.h" //#include "mlm_spline.h" #include "bspline.h" @@ -108,8 +108,7 @@ class mlmodel_module_t : public pvmodule_t double I_0ref; double I_Lref; double Vbi; -// tk::spline iamSpline; - BSpline m_bspline3; + std::unique_ptr m_bspline3; }; diff --git a/shared/lib_ondinv.cpp b/shared/lib_ondinv.cpp index 078aaa4a39..f2660af72d 100644 --- a/shared/lib_ondinv.cpp +++ b/shared/lib_ondinv.cpp @@ -43,8 +43,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "lib_ondinv.h" -#include "bsplinebuilder.h" -#include "datatable.h" +#include +#include const int TEMP_DERATE_ARRAY_LENGTH = 6; @@ -203,8 +203,7 @@ void ond_inverter::initializeManual() Pdc_threshold = 2; std::vector ondspl_X; std::vector ondspl_Y; - DenseVector xSamples(1); - DataTable samples; + std::vector xSamples(1); // int splineIndex; // bool switchoverDone; @@ -271,14 +270,14 @@ void ond_inverter::initializeManual() } */ // SPLINTER - samples.clear(); + DataTable samples; x_max[j] = ondspl_X.back(); for (size_t k = 0; k < ondspl_X.size() && k < ondspl_Y.size(); k++) { - xSamples(0) = ondspl_X[k]; - samples.addSample(xSamples, ondspl_Y[k]); + xSamples[0] = ondspl_X[k]; + samples.add_sample(xSamples, ondspl_Y[k]); } - m_bspline3[j] = BSpline::Builder(samples).degree(3).build(); + m_bspline3[j] = std::make_unique(bspline_interpolator(samples, 3)); } ondIsInitialized = true; @@ -310,7 +309,7 @@ double ond_inverter::calcEfficiency(double Pdc, int index_eta) { { // eta = effSpline[splineIndex][index_eta](Pdc); x(0) = Pdc; - eta = (m_bspline3[index_eta]).eval(x); + eta = (*m_bspline3[index_eta]).eval(x)[0]; } else { diff --git a/shared/lib_ondinv.h b/shared/lib_ondinv.h index efae89ce34..60415c71e1 100644 --- a/shared/lib_ondinv.h +++ b/shared/lib_ondinv.h @@ -32,10 +32,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef __lib_ondinv_h #define __lib_ondinv_h +#include #include #include //#include "mlm_spline.h" // spline interpolator for efficiency curves -#include "bspline.h" +#include using namespace std; using namespace SPLINTER; @@ -63,10 +64,10 @@ class ond_inverter double INomDC; // [A] double INomAC; // [A] double IMaxAC; // [A] - double TPNom; // [°C] - double TPMax; // [°C] - double TPLim1; // [°C] - double TPLimAbs; // [°C] + double TPNom; // [�C] + double TPMax; // [�C] + double TPLim1; // [�C] + double TPLimAbs; // [�C] double PLim1; // [kW] double PLimAbs; // [kW] double VNomEff[3]; // [V] @@ -87,7 +88,7 @@ class ond_inverter /* inputs */ double Pdc, /* Input power to inverter (Wdc) */ double Vdc, /* Voltage input to inverter (Vdc) */ - double Tamb, /* Ambient temperature (°C) */ + double Tamb, /* Ambient temperature (�C) */ /* outputs */ double *Pac, /* AC output power (Wac) */ @@ -115,9 +116,7 @@ class ond_inverter bool ondIsInitialized; int noOfEfficiencyCurves; -// tk::spline effSpline[2][3]; -// BSpline m_bspline3[2][3]; - BSpline m_bspline3[3]; + std::vector> m_bspline3; double x_max[3]; double x_lim[3]; double Pdc_threshold; @@ -131,8 +130,6 @@ class ond_inverter double T_array[6]; double PAC_array[6]; - - }; #endif diff --git a/shared/lib_ortools.cpp b/shared/lib_ortools.cpp new file mode 100644 index 0000000000..e9e863664a --- /dev/null +++ b/shared/lib_ortools.cpp @@ -0,0 +1,59 @@ +#include "ortools/linear_solver/linear_solver.h" +#include "lib_ptes_chp_dispatch.h" +#include "lib_ortools.h" + +using namespace operations_research; + + +void example::contraint_from_function(MPVariable* var1, MPVariable* var2, double bound, std::string name_pre) { + std::string name = name_pre + "ct" + std::to_string(2) + "end"; + MPConstraint* const ct = solver->MakeRowConstraint(0.0, bound, name); + ct->SetCoefficient(var1, 1); + ct->SetCoefficient(var2, 1); +} + +void example::BasicExample() { + // Create the linear solver. + //std::unique_ptr solver(MPSolver::CreateSolver("XPRESS")); + //std::unique_ptr solver(MPSolver::CreateSolver("SCIP")); + + if (!solver) { + LOG(WARNING) << "Solver unavailable."; + return; + } + + // Creating an array of variables x (another way) + std::vector x, y; + solver->MakeNumVarArray(2, 0.0, 2.0, "x", &x); + //solver->MakeIntVarArray(2, 0.0, 1.0, "y", &y); // binary variable + solver->MakeBoolVarArray(2, "y", &y); // binary variable + + LOG(INFO) << "Number of variables = " << solver->NumVariables(); + + // Create a linear constraint, 0 <= x + y <= 2. + contraint_from_function(x[0], x[1], data, "continous"); + contraint_from_function(y[0], y[1], 1., "binary"); + + LOG(INFO) << "Number of constraints = " << solver->NumConstraints(); + + // Create the objective function + MPObjective* const objective = solver->MutableObjective(); + for (int i = 0; i < 2; ++i) { + objective->SetCoefficient(x[i], obj_coeff[i]); + objective->SetCoefficient(y[i], obj_coeff[i]/4.0); + } + objective->SetMaximization(); + + solver->Solve(); + + LOG(INFO) << "Solution:" << std::endl; + LOG(INFO) << "Objective value = " << objective->Value(); + for (int i = 0; i < 2; ++i) { + LOG(INFO) << "x[" << i << "] = " << x[i]->solution_value(); + } + for (int i = 0; i < 2; ++i) { + LOG(INFO) << "y[" << i << "] = " << y[i]->solution_value(); + } + LOG(INFO) << "Constraint name = " << solver->constraint(0)->name(); + LOG(INFO) << "Constraint name = " << solver->constraint(1)->name(); +} diff --git a/shared/lib_ortools.h b/shared/lib_ortools.h new file mode 100644 index 0000000000..2ded7990ac --- /dev/null +++ b/shared/lib_ortools.h @@ -0,0 +1,20 @@ +#pragma once +#include "ortools/linear_solver/linear_solver.h" + +using namespace operations_research; + +class example { + std::unique_ptr solver; + +public: + example() { + solver = std::unique_ptr(MPSolver::CreateSolver("XPRESS")); + } + + double data; + std::vector obj_coeff; + + void contraint_from_function(MPVariable* var1, MPVariable* var2, double bound, std::string name_pre); + + void BasicExample(); +}; diff --git a/shared/lib_ptes_chp_dispatch.cpp b/shared/lib_ptes_chp_dispatch.cpp new file mode 100644 index 0000000000..cb7832ae47 --- /dev/null +++ b/shared/lib_ptes_chp_dispatch.cpp @@ -0,0 +1,939 @@ +#include +#include +#include +#include +#include // for table output + +#include "ortools/base/timer.h" +#include "lib_ptes_chp_dispatch.h" +using namespace operations_research; + +void PTES_CHP_Dispatch_Data::setPrices(std::string sell_price_file, double average_price_multipler /*$/MWhe*/, + double heat_price /*$/MWht*/) { + set_data_by_file(sell_price, sell_price_file); + for (int t = 0; t < sell_price.size(); t++) { + sell_price[t] *= average_price_multipler; + } + purchase_price = sell_price; // sell and purchase price equal + heat_sell_price.resize(n_periods, heat_price); // Set to a constant of $20/MWht +}; + +void PTES_CHP_Dispatch_Data::setHeatLoad(std::string heat_load_file, double multipler /*-*/) { + set_data_by_file(heat_demand, heat_load_file); + for (int t = 0; t < heat_demand.size(); t++) { + heat_demand[t] *= multipler; + } +} + +void PTES_CHP_Dispatch_Data::set_data_by_file(std::vector& data, std::string filepath) { + + std::vector< std::string> data_str; + std::ifstream datafile(filepath); + + char line[250]; + if (datafile.is_open()) { + while (datafile) { + datafile.getline(line, 250); + data_str.push_back(line); + } + } + + data.resize(data_str.size() - 1, 0.); + for (int i = 0; i < data_str.size() - 1; i++) { + data.at(i) = std::stod(data_str.at(i)); + } +} + +void PTES_CHP_Dispatch_Data::setDefaultAssumptions(PtesDesign design) { + eta_amb.resize(n_periods, 1.); // assuming no ambient temperature impact + + // Cost parameters + cycle_ramping_cost = 0.3; // $/MWt + cycle_start_cost = 20.0 * design.cycle_cap; // $/start + heat_pump_ramp_cost = 0.6; // $/MWe + heat_pump_start_cost = 5.0 * design.hp_cap; // $/start + + // Power cycle parameters + double cycle_des_heat = design.cycle_cap / design.cycle_eta; + e_pb_startup = cycle_des_heat * 0.25; // 15-minutes at design + q_pb_max = cycle_des_heat; // Cycle heat input (max) + q_pb_min = cycle_des_heat * 0.3; // 30% turn down + q_pb_startup = cycle_des_heat * 0.25; + w_pb_max = design.cycle_cap; + eta_p = (w_pb_max - w_pb_max * 0.15) / (q_pb_max - q_pb_min); // Assuming 15% power at min turndown + eta_d = 1.0; // this is used to un-normalize the ambient correction -> ignoring at the moment + q_rc = ((cycle_des_heat) - design.cycle_cap) * 0.5320755; // Assume the 60 MWt default value + + // Cycle initial conditions + is_pb_starting0 = false; // Assume cycle is off and not starting up + is_pb_operating0 = false; + q_pb0 = 0.0; + e_pb_start0 = 0.0; + + // minimum up and down time parameters + min_up_down_params.down_time_min = 2.0; + min_up_down_params.up_time_min = 2.0; + min_up_down_params.down_time0 = 10.0; // Enable cycle to start up in period 1 + min_up_down_params.up_time0 = 0.0; + min_up_down_params.time_elapsed.clear(); + for (int t = 0; t < n_periods; t++) { + min_up_down_params.time_elapsed.push_back(delta * (t + 1)); + } + + // Heat pump parameters + e_hp_startup = design.hp_cap * 0.25; // MWhe -> 15-minutes at design + w_hp_max = design.hp_cap; // MWe + w_hp_min = design.hp_cap * 0.3; // MWe -> Assuming a 30% turndown + w_hp_startup = design.hp_cap * 0.25; // MWe + q_hp_max = design.hp_cap * design.hp_cop; + kappa_p = (q_hp_max - q_hp_max * 0.15) / (w_hp_max - w_hp_min); // Assuming 15% heat at min turndown + q_rh = 0.0; // Assuming zero heat rejected during charging + + // Heat pump initial conditions + is_hp_starting0 = false; // Assume heat is off and not starting up + is_hp_operating0 = false; + w_hp0 = 0.0; + e_hp_start0 = 0.0; + + // TES parameters + e_tes_max = design.tes_cap; + e_tes0 = design.tes_cap * 0.05; // Assuming 5% full + e_loss = design.tes_cap * 0.0004; // Determined from SAM's default PTES case + + // Heat offtaker TES parameters + e_ot_max = design.tes_cap * 0.1; // Assuming off-taker storage is 10% + e_ot0 = e_ot_max * 0.05; + e_ot_loss = e_ot_max * 0.0004; // Determined from SAM's default PTES case + q_tes_max = 60.; // TODO: May need to update +} + +ptes_chp_dispatch::ptes_chp_dispatch() { + + initializeSolver(); +} + +void ptes_chp_dispatch::initializeSolver() { + solver = CreateSolver("SCIP"); + //solver = CreateSolver("SCIP"); + //solver = std::unique_ptr(MPSolver::CreateSolver("SCIP")); + if (!solver) { + LOG(WARNING) << "Solver unavailable."; + return; + } + //LOG(INFO) << solver->SolverVersion(); + //solver->SetNumThreads(4); + solver->EnableOutput(); + solver->set_time_limit(180*60*1000); //micro-seconds 120*60 + + //solver_params.SetIntegerParam(MPSolverParameters::PRESOLVE, MPSolverParameters::PresolveValues::PRESOLVE_OFF); + + solver_params.SetDoubleParam(MPSolverParameters::DoubleParam::RELATIVE_MIP_GAP, 1.e-2); // 1.e-2 + + //solver_params.SetDoubleParam(MPSolverParameters::DoubleParam::DUAL_TOLERANCE, 1.e-3); + //solver_params.SetDoubleParam(MPSolverParameters::DoubleParam::PRIMAL_TOLERANCE, 1.e-3); +} + +std::unique_ptr ptes_chp_dispatch::CreateSolver(const std::string& solver_id) { + return std::unique_ptr(MPSolver::CreateSolver(solver_id)); +} + +void ptes_chp_dispatch::createVariables() { + // Continous variables + solver->MakeNumVarArray(params.n_periods, 0.0, params.q_pb_max, "q_c", &vars.q_c); + solver->MakeNumVarArray(params.n_periods, 0.0, params.q_pb_max, "q_delta_c", &vars.q_delta_c); + solver->MakeNumVarArray(params.n_periods, 0.0, params.q_hp_max, "q_h", &vars.q_h); + solver->MakeNumVarArray(params.n_periods, 0.0, std::max(params.q_rc, params.q_rh), "q_r", &vars.q_r); + solver->MakeNumVarArray(params.n_periods, 0.0, params.q_tes_max, "q_tes", &vars.q_tes); + solver->MakeNumVarArray(params.n_periods, 0.0, MPSolver::infinity(), "q_s", &vars.q_s); + solver->MakeNumVarArray(params.n_periods, 0.0, params.e_tes_max, "s", &vars.s); + solver->MakeNumVarArray(params.n_periods, 0.0, config.is_offtaker_tes ? params.e_ot_max : 0.0, "s_ot", &vars.s_ot); + solver->MakeNumVarArray(params.n_periods, 0.0, MPSolver::infinity(), "u_csu", &vars.u_csu); + solver->MakeNumVarArray(params.n_periods, 0.0, MPSolver::infinity(), "u_hsu", &vars.u_hsu); + solver->MakeNumVarArray(params.n_periods, 0.0, params.w_pb_max * 1.2, "w_c", &vars.w_c); + solver->MakeNumVarArray(params.n_periods, 0.0, params.w_hp_max, "w_delta_h", &vars.w_delta_h); + solver->MakeNumVarArray(params.n_periods, 0.0, params.w_hp_max, "w_h", &vars.w_h); + // Binary variables + solver->MakeBoolVarArray(params.n_periods, "y_c", &bin_vars.y_c); + solver->MakeBoolVarArray(params.n_periods, "y_cgb", &bin_vars.y_cgb); + solver->MakeBoolVarArray(params.n_periods, "y_cge", &bin_vars.y_cge); + solver->MakeBoolVarArray(params.n_periods, "y_csu", &bin_vars.y_csu); + solver->MakeBoolVarArray(params.n_periods, "y_csup", &bin_vars.y_csup); + solver->MakeBoolVarArray(params.n_periods, "y_h", &bin_vars.y_h); + solver->MakeBoolVarArray(params.n_periods, "y_hsu", &bin_vars.y_hsu); + solver->MakeBoolVarArray(params.n_periods, "y_hsup", &bin_vars.y_hsup); + + LOG(INFO) << "Number of variables = " << solver->NumVariables(); +} + +void ptes_chp_dispatch::createConstraints() { + /*==== Charging - Heat Pump ====*/ + // Heat pump startup inventory + // u_hsu[t] <= u_hsu[t-1] + Delta * W^hsu * y_hsu[t] + create_startup_inventory_constraint(vars.u_hsu, bin_vars.y_hsu, params.delta * params.w_hp_startup, params.e_hp_start0, "hp_start_inv"); + // Heat pump inventory nonzero + // uhsu[t] <= Eh * yhsu[t] + create_inventory_nonzero_constraint(vars.u_hsu, bin_vars.y_hsu, params.e_hp_startup * 1.00001, "hp_inv_nonzero"); + // Heat pump operation allowed when: + // yh[t] <= uhsu[t] / Eh + yh[t-1] + create_operation_allowed_constraint(bin_vars.y_h, vars.u_hsu, params.e_hp_startup, params.is_hp_operating0, "hp_op_allowed"); + // Heat pump startup can't be enabled after a time step where it was operating + // yhsu[t] + yh[t-1] <= 1 + create_startup_wait_constraint(bin_vars.y_hsu, bin_vars.y_h, params.is_hp_operating0, "hp_su_wait"); + // Heat pump minimum power input requirement + // wh[t] >= Wh{min} * yh[t] + create_minimum_operation_constraint(vars.w_h, bin_vars.y_h, params.w_hp_min, "hp_min_input_power"); + // Limits the electrical power to the heat pump during periods of startup + // wh[t] + Whsu * yhsu[t] <= Wh{max} * yh[t] + create_maximum_operation_wstartup_constraint(vars.w_h, bin_vars.y_hsu, bin_vars.y_h, params.w_hp_startup, params.w_hp_max, "hp_max_input_power"); + // Heat production linearization (heat output as function of power input) + // qh[t] = Kp * wh[t] + ( Qh{max} - Kp * Wh{max}) * yh[t] + double intercept = params.q_hp_max - params.kappa_p * params.w_hp_max; + create_linear_production_constraint(vars.q_h, vars.w_h, bin_vars.y_h, params.kappa_p, intercept, params.eta_amb, "hp_heat_production"); + // Heat pump ramping (positive change) + // wdeltah[t] >= wh[t] - wh[t-1] + create_positive_ramping_constraint(vars.w_delta_h, vars.w_h, params.w_hp0, "hp_ramping"); + // Heat pump startup penalty + // yhsup[t] >= yhsu[t] - yhsu[t-1] + create_startup_penalty_constraint(bin_vars.y_hsup, bin_vars.y_hsu, params.is_hp_starting0, "hp_startup_penalty"); + + /*==== Discharging - Closed Brayton Cycle ====*/ + // Cycle startup inventory + // ucsu[t] <= ucsu[t-1] + Delta * Q^csu * ycsu[t] + create_startup_inventory_constraint(vars.u_csu, bin_vars.y_csu, params.delta * params.q_pb_startup, params.e_pb_start0, "pc_start_inv"); + // Cycle inventory nonzero + // ucsu[t] <= Ec * ycsu[t] + create_inventory_nonzero_constraint(vars.u_csu, bin_vars.y_csu, params.e_pb_startup * 1.00001, "pc_inv_nonzero"); + // Cycle operation allowed when: + // yc[t] <= ucsu[t] / Ec + yc[t-1] + create_operation_allowed_constraint(bin_vars.y_c, vars.u_csu, params.e_pb_startup, params.is_pb_operating0, "pc_op_allowed"); + // Cycle startup can't be enabled after a time step where it was operating + // ycsu[t] + yc[t-1] <= 1 + create_startup_wait_constraint(bin_vars.y_csu, bin_vars.y_c, params.is_pb_operating0, "pc_su_wait"); + // Cycle minimum heat input requirement + // qc[t] >= Qc{min} * yc[t] + create_minimum_operation_constraint(vars.q_c, bin_vars.y_c, params.q_pb_min, "pc_min_input_heat"); + // Limits the thermal power to the cycle during periods of startup + // qc[t] + Qcsu * ycsu[t] <= Qc{max} * yc[t] + create_maximum_operation_wstartup_constraint(vars.q_c, bin_vars.y_csu, bin_vars.y_c, params.q_pb_startup, params.q_pb_max, "pc_max_input_heat"); + // Power production linearization (power output as function of heat input) + // wc[t] = eta^amb[t] * (etap * qc[t] + ( Wc{max} - etap * Qc{max}) * yc[t]) + intercept = params.w_pb_max - params.eta_p * params.q_pb_max; + create_linear_production_constraint(vars.w_c, vars.q_c, bin_vars.y_c, params.eta_p, intercept, params.eta_amb, "hp_heat_production"); + // Cycle ramping (positive change) + // qdeltac[t] >= qc[t] - qc[t-1] + create_positive_ramping_constraint(vars.q_delta_c, vars.q_c, params.q_pb0, "pc_ramping"); + // Cycle startup penalty + // ycsup[t] >= ycsu[t] - ycsu[t-1] + create_startup_penalty_constraint(bin_vars.y_csup, bin_vars.y_csu, params.is_pb_starting0, "pc_startup_penalty"); + // Charging and discharging cannot coincide + // yh[t] + yc[t] <= 1 + create_set_packing_constraint(bin_vars.y_h, bin_vars.y_c, "char_dischar_pack"); + // Minimum up- and down- constraints + // ycgb[t] - ycge[t] = y_c[t] - y_c[t-1] + // sum{tp in Tau : 0 <= deltaE[t] - deltaE[tp] < Yu} ycgb[tp] <= y[t] forall t in Tau : deltaE[t] > (Yu-Yu0)*y0 + // sum{tp in Tau : 0 <= deltaE[t] - deltaE[tp] < Yd} ycge[tp] <= 1 - y[t] forall t in Tau : deltaE[t] > (Yd-Yd0)*(1-y0) + // y_c[t] = y0 forall t in Tau : deltaE[t] <= max{ (Yu - Yu0) * y0 , (Yd - Yd0) * (1 - y0) } + create_min_up_down_constraints(bin_vars.y_c, bin_vars.y_cgb, bin_vars.y_cge, params.is_pb_operating0, params.min_up_down_params, ""); + + /*==== Thermal Energy Storage ====*/ + // Storage energy balance + // s[t] - s[t-1] = Delta * ( qh[t] - qc[t] - Qcsu * ycsu[t]) - Qloss + // if heat demand can be met with PTES hot TES + // s[t] - s[t-1] = Delta * ( qh[t] - qc[t] - Qcsu * ycsu[t] - q_tes[t]) - E_loss + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + MPConstraint* constraint; + std::string name = "tes_balance[" + std::to_string(t) + "]"; + if (t == 0) { + constraint = solver->MakeRowConstraint(params.e_tes0 - params.e_loss, params.e_tes0 - params.e_loss, name); + } + else { + constraint = solver->MakeRowConstraint(-params.e_loss, -params.e_loss, name); + constraint->SetCoefficient(vars.s[t - 1], -1.0); + } + constraint->SetCoefficient(vars.s[t], 1.0); + constraint->SetCoefficient(vars.q_h[t], -params.delta); + constraint->SetCoefficient(vars.q_c[t], params.delta); + constraint->SetCoefficient(bin_vars.y_csu[t], params.delta * params.q_pb_startup); + if (config.is_heat_from_tes_allowed) constraint->SetCoefficient(vars.q_tes[t], params.delta); + } + + /*==== Heat Off-taker ====*/ + // Rejected heat occurs during charging and/or discharging + // q_r[t] <= Qrh * y_h[t] + Qrc * y_c[t] + // TODO: Partload... + // q_r[t] <= Qrh / Qh{max} * q_h[t] + Qrc / Qc{max} * q_c[t] + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + MPConstraint* constraint; + std::string name = "heat_reject[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 0.0, name); + constraint->SetCoefficient(vars.q_r[t], 1.0); + if (config.is_charge_heat_reject) constraint->SetCoefficient(bin_vars.y_h[t], -params.q_rh); + if (config.is_discharge_heat_reject) constraint->SetCoefficient(bin_vars.y_c[t], -params.q_rc); + //if (is_charge_heat_reject) constraint->SetCoefficient(vars.q_h[t], -params.q_rh / params.q_hp_max); + //if (is_discharge_heat_reject) constraint->SetCoefficient(vars.q_c[t], -params.q_rc / params.q_pb_max); + } + + // Heat off-taker demand must be met + // q_s[t] == Q_d[t] + // *** OR *** + // Sold heat must be less than heat off-taker demand + // q_s[t] <= Q_d[t] + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + MPConstraint* constraint; + std::string name = "heat_demand[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(config.is_heat_demand_required ? params.heat_demand[t] : -MPSolver::infinity(), params.heat_demand[t], name); + constraint->SetCoefficient(vars.q_s[t], 1.0); + } + + if (!config.is_offtaker_tes) { + params.e_ot0 = 0.0; // Must be set to zero when not available + params.e_ot_loss = 0.0; + } + + // Heat off-taker storage energy balance + // s_ot[t] - s_ot[t-1] = Delta * ( q_r[t] - q_s[t]) - Eloss + // if heat demand can be met with PTES hot TES + // s_ot[t] - s_ot[t-1] = Delta * ( q_r[t] + q_tes[t] - q_s[t]) - E_ot_loss + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + MPConstraint* constraint; + std::string name = "off_taker_tes_balance[" + std::to_string(t) + "]"; + if (t == 0) { + constraint = solver->MakeRowConstraint(params.e_ot0 - params.e_ot_loss, params.e_ot0 - params.e_ot_loss, name); + } + else { + constraint = solver->MakeRowConstraint(-params.e_ot_loss, -params.e_ot_loss, name); + constraint->SetCoefficient(vars.s_ot[t - 1], -1.0); + } + constraint->SetCoefficient(vars.s_ot[t], 1.0); + constraint->SetCoefficient(vars.q_r[t], -params.delta); + if (config.is_heat_from_tes_allowed) constraint->SetCoefficient(vars.q_tes[t], -params.delta); + constraint->SetCoefficient(vars.q_s[t], params.delta); + } + + LOG(INFO) << "Number of constraints = " << solver->NumConstraints(); +} + +void ptes_chp_dispatch::createObjectiveFunction() { + /*==== Objective Function ====*/ + objective = solver->MutableObjective(); + double common_coeff; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + common_coeff = params.delta * std::pow(params.time_weighting, t); + objective->SetCoefficient(vars.w_c[t], common_coeff * params.sell_price[t]); + if (config.is_heat_valued) { + objective->SetCoefficient(vars.q_s[t], common_coeff * params.heat_sell_price[t]); + } + common_coeff = -params.delta * params.purchase_price[t] * (1. / std::pow(params.time_weighting, t)); + objective->SetCoefficient(vars.w_h[t], common_coeff); + common_coeff *= params.w_hp_startup; + objective->SetCoefficient(bin_vars.y_hsu[t], common_coeff); + // Cost terms + common_coeff = -(1. / std::pow(params.time_weighting, t)); + objective->SetCoefficient(bin_vars.y_csup[t], common_coeff * params.cycle_start_cost); + objective->SetCoefficient(vars.q_delta_c[t], common_coeff * params.cycle_ramping_cost); + objective->SetCoefficient(bin_vars.y_hsup[t], common_coeff * params.heat_pump_start_cost); + objective->SetCoefficient(vars.w_delta_h[t], common_coeff * params.heat_pump_ramp_cost); + } + objective->SetMaximization(); +} + +double ptes_chp_dispatch::optimize(std::string resultsfilepath) { + // Create variables + createVariables(); // This could be moved to the constructor class + + // Create the constraints + createConstraints(); + + // Create the objective function + createObjectiveFunction(); + + //solver->EnableOutput(); + std::clock_t c_start = std::clock(); + MPSolver::ResultStatus result_status = solver->Solve(solver_params); + absl::Duration wall_time = solver->DurationSinceConstruction(); + std::clock_t c_end = std::clock(); + double time_elapsed_sec = (c_end - c_start) / CLOCKS_PER_SEC; + + // Check that the problem has an optimal solution. + if (result_status != MPSolver::OPTIMAL) { // How to handle infeasibilities + //LOG(FATAL) << "The problem does not have an optimal solution."; + solver->Clear(); + vars.Clear(); + bin_vars.Clear(); + return 0.0; + } + + printVariableValuesToConsole(wall_time); + printResultsFile(resultsfilepath); + + // Must clear solver and variables before next solve + solver->Clear(); + vars.Clear(); + bin_vars.Clear(); + + return time_elapsed_sec; +} + +double ptes_chp_dispatch::rollingHorizonoptimize(int opt_horizon, int roll_horizon, std::string resultsfilepath) { + int original_horizon = params.n_periods; + + // Save full vectors + std::vector f_eta_amb = params.eta_amb; + std::vector f_heat_sell_price = params.heat_sell_price; + std::vector f_purchase_price = params.purchase_price; + std::vector f_sell_price = params.sell_price; + std::vector f_heat_demand = params.heat_demand; + + // for loop to set up model, solve, and save results + double n_solves = (int)std::ceil(params.n_periods / roll_horizon); + + params.min_up_down_params.time_elapsed.clear(); + for (int t = 0; t < opt_horizon; t++) { + params.min_up_down_params.time_elapsed.push_back(params.delta * (t + 1)); + } + + std::clock_t c_start = std::clock(); + for (int s = 0; s < n_solves; ++s) { + int sidx = (int)(s * roll_horizon); // window start + //int eidx = (int)(sidx + opt_horizon); // window end + params.n_periods = opt_horizon; + // update parameter vectors + params.eta_amb.resize(params.n_periods); + params.heat_sell_price.resize(params.n_periods); + params.purchase_price.resize(params.n_periods); + params.sell_price.resize(params.n_periods); + params.heat_demand.resize(params.n_periods); + for (int i = 0; i < params.n_periods; ++i) { + int original_idx = sidx + i; + if (original_idx >= original_horizon) original_idx -= original_horizon; // start back at the begining + params.eta_amb[i] = f_eta_amb[original_idx]; + params.heat_sell_price[i] = f_heat_sell_price[original_idx]; + params.purchase_price[i] = f_purchase_price[original_idx]; + params.sell_price[i] = f_sell_price[original_idx]; + params.heat_demand[i] = f_heat_demand[original_idx]; + } + + // create problem and solve + LOG(INFO) << " Solving Optimization Horizon: " << s << std::endl; + createVariables(); + createConstraints(); + createObjectiveFunction(); + MPSolver::ResultStatus result_status = solver->Solve(solver_params); + updateInitialConditions(roll_horizon - 1); + //change n_periods so result file loop works + params.n_periods = roll_horizon; + if (s == 0) + printResultsFile(resultsfilepath); // create file with header + else + printResultsFile(resultsfilepath, true); // append results + + // Must clear solver and variables before next solve + solver->Clear(); + vars.Clear(); + bin_vars.Clear(); + } + + std::clock_t c_end = std::clock(); + double time_elapsed_sec = (c_end - c_start) / CLOCKS_PER_SEC; + LOG(INFO) << "CPU time used: " << time_elapsed_sec << " sec" << std::endl; + + // Return class back to original state + params.n_periods = original_horizon; + params.eta_amb = f_eta_amb; + params.heat_sell_price = f_heat_sell_price; + params.purchase_price = f_purchase_price; + params.sell_price = f_sell_price; + params.heat_demand = f_heat_demand; + + return time_elapsed_sec; +} + +void ptes_chp_dispatch::updateInitialConditions(int init_t) { + // Cycle + params.is_pb_starting0 = bin_vars.y_csu[init_t]->solution_value() ? true : false; + params.is_pb_operating0 = bin_vars.y_c[init_t]->solution_value() ? true : false; + params.q_pb0 = params.is_pb_operating0 ? vars.q_c[init_t]->solution_value() : 0.0; + params.e_pb_start0 = params.is_pb_starting0 ? vars.u_csu[init_t]->solution_value() : 0.0; + // Up time and down time + params.min_up_down_params.time_elapsed.clear(); + for (int t = 0; t < params.n_periods; t++) { + params.min_up_down_params.time_elapsed.push_back(params.delta * (t + 1)); + } + double init_up_time = 0.0; + double init_down_time = 0.0; + if (params.is_pb_operating0) { // cycle is up + for (int t = init_t; t > 0; t--) { + if (bin_vars.y_c[t]->solution_value()) { + init_up_time += params.delta; + } + else break; + } + } + else { + for (int t = init_t; t > 0; t--) { + if (!bin_vars.y_c[t]->solution_value()) { + init_down_time += params.delta; + } + else break; + } + } + params.min_up_down_params.up_time0 = init_up_time; + params.min_up_down_params.down_time0 = init_down_time; + // Heat pump + params.is_hp_starting0 = bin_vars.y_hsu[init_t]->solution_value() ? true : false; + params.is_hp_operating0 = bin_vars.y_h[init_t]->solution_value() ? true : false; + params.w_hp0 = params.is_hp_operating0 ? vars.w_h[init_t]->solution_value() : 0.0; + params.e_hp_start0 = params.is_hp_starting0 ? vars.u_hsu[init_t]->solution_value() : 0.0; + // Storage + params.e_tes0 = std::max(vars.s[init_t]->solution_value(), 0.0); + // Heat off-taker Storage + params.e_ot0 = std::max(vars.s_ot[init_t]->solution_value(), 0.0); +} + +void ptes_chp_dispatch::printVariableValuesToConsole(absl::Duration wall_time) { + LOG(INFO) << "Solution:" << std::endl; + LOG(INFO) << "Objective value = " << objective->Value() << std::endl; + LOG(INFO) << "Interations = " << solver->iterations() << std::endl; + LOG(INFO) << "Wall Time = " << wall_time << std::endl; + LOG(INFO) << "==================================================================" << std::endl; + LOG(INFO) << " Cycle Variable Values " << std::endl; + LOG(INFO) << "==================================================================" << std::endl; + int col_width = 10; + double tol = 1.e-3; + LOG(INFO) << std::setfill(' ') << std::left << std::setw(6) << "Time" + << std::left << std::setw(col_width) << "price" + << std::left << std::setw(col_width) << "y_csup" + << std::left << std::setw(col_width) << "y_csu" + << std::left << std::setw(col_width) << "u_csu" + << std::left << std::setw(col_width) << "y_c" + << std::left << std::setw(col_width) << "w_c" + << std::left << std::setw(col_width) << "q_c" + << std::left << std::setw(col_width) << "q_delta_c" + << std::left << std::setw(col_width) << "y_cgb" + << std::left << std::setw(col_width) << "y_cge" + << std::endl; + for (int t = 0; t < std::min(params.n_periods, 48); ++t) { + LOG(INFO) << std::setfill(' ') << std::left << std::setw(6) << t + << std::left << std::setw(col_width) << params.sell_price[t] + << std::left << std::setw(col_width) << (bin_vars.y_csup[t]->solution_value() ? 1 : 0) + << std::left << std::setw(col_width) << (bin_vars.y_csu[t]->solution_value() ? 1 : 0) + << std::left << std::setw(col_width) << ((std::abs(vars.u_csu[t]->solution_value()) < tol) ? 0.0 : vars.u_csu[t]->solution_value()) + << std::left << std::setw(col_width) << (bin_vars.y_c[t]->solution_value() ? 1 : 0) + << std::left << std::setw(col_width) << ((std::abs(vars.w_c[t]->solution_value()) < tol) ? 0.0 : vars.w_c[t]->solution_value()) + << std::left << std::setw(col_width) << ((std::abs(vars.q_c[t]->solution_value()) < tol) ? 0.0 : vars.q_c[t]->solution_value()) + << std::left << std::setw(col_width) << ((std::abs(vars.q_delta_c[t]->solution_value()) < tol) ? 0.0 : vars.q_delta_c[t]->solution_value()) + << std::left << std::setw(col_width) << (bin_vars.y_cgb[t]->solution_value() ? 1 : 0) + << std::left << std::setw(col_width) << (bin_vars.y_cge[t]->solution_value() ? 1 : 0) + << std::endl; + } + LOG(INFO) << "==================================================================" << std::endl; + LOG(INFO) << " Heat Pump Variable Values " << std::endl; + LOG(INFO) << "==================================================================" << std::endl; + LOG(INFO) << std::setfill(' ') << std::left << std::setw(6) << "Time" + << std::left << std::setw(col_width) << "s" + << std::left << std::setw(col_width) << "y_hsup" + << std::left << std::setw(col_width) << "y_hsu" + << std::left << std::setw(col_width) << "u_hsu" + << std::left << std::setw(col_width) << "y_h" + << std::left << std::setw(col_width) << "w_h" + << std::left << std::setw(col_width) << "q_h" + << std::left << std::setw(col_width) << "w_delta_h" + << std::endl; + for (int t = 0; t < std::min(params.n_periods, 48); ++t) { + LOG(INFO) << std::setfill(' ') << std::left << std::setw(6) << t + << std::left << std::setw(col_width) << ((std::abs(vars.s[t]->solution_value()) < tol) ? 0.0 : vars.s[t]->solution_value()) + << std::left << std::setw(col_width) << (bin_vars.y_hsup[t]->solution_value() ? 1 : 0) + << std::left << std::setw(col_width) << (bin_vars.y_hsu[t]->solution_value() ? 1 : 0) + << std::left << std::setw(col_width) << ((std::abs(vars.u_hsu[t]->solution_value()) < tol) ? 0.0 : vars.u_hsu[t]->solution_value()) + << std::left << std::setw(col_width) << (bin_vars.y_h[t]->solution_value() ? 1 : 0) + << std::left << std::setw(col_width) << ((std::abs(vars.w_h[t]->solution_value()) < tol) ? 0.0 : vars.w_h[t]->solution_value()) + << std::left << std::setw(col_width) << ((std::abs(vars.q_h[t]->solution_value()) < tol) ? 0.0 : vars.q_h[t]->solution_value()) + << std::left << std::setw(col_width) << ((std::abs(vars.w_delta_h[t]->solution_value()) < tol) ? 0.0 : vars.w_delta_h[t]->solution_value()) + << std::endl; + } + LOG(INFO) << "==================================================================" << std::endl; + LOG(INFO) << " Heat Off-Taker Variable Values " << std::endl; + LOG(INFO) << "==================================================================" << std::endl; + LOG(INFO) << std::setfill(' ') << std::left << std::setw(6) << "Time" + << std::left << std::setw(col_width) << "heat_P" + << std::left << std::setw(col_width) << "ht_dem" + << std::left << std::setw(col_width) << "s_ot" + << std::left << std::setw(col_width) << "q_s" + << std::left << std::setw(col_width) << "q_r" + << std::left << std::setw(col_width) << "q_tes" + << std::endl; + for (int t = 0; t < std::min(params.n_periods, 48); ++t) { + LOG(INFO) << std::setfill(' ') << std::left << std::setw(6) << t + << std::left << std::setw(col_width) << params.heat_sell_price[t] + << std::left << std::setw(col_width) << params.heat_demand[t] + << std::left << std::setw(col_width) << ((std::abs(vars.s_ot[t]->solution_value()) < tol) ? 0.0 : vars.s_ot[t]->solution_value()) + << std::left << std::setw(col_width) << ((std::abs(vars.q_s[t]->solution_value()) < tol) ? 0.0 : vars.q_s[t]->solution_value()) + << std::left << std::setw(col_width) << ((std::abs(vars.q_r[t]->solution_value()) < tol) ? 0.0 : vars.q_r[t]->solution_value()) + << std::left << std::setw(col_width) << ((std::abs(vars.q_tes[t]->solution_value()) < tol) ? 0.0 : vars.q_tes[t]->solution_value()) + << std::endl; + } +} + +void ptes_chp_dispatch::printResultsFile(std::string filepath, bool append) { + std::ofstream outputfile; + if (append) + outputfile.open(filepath, std::ios_base::app); + else { + // Only print header when not appending + outputfile.open(filepath); + std::string var_header = "Time, Objective, Objective_wo_weight, Price, y_csup, y_csu, u_csu, y_c, w_c, q_c, q_delta_c, y_cgb, y_cge, " + "s, y_hsup, y_hsu, u_hsu, y_h, w_h, q_h, w_delta_h, " + "heat_price, heat_demand, s_ot, q_s, q_r, q_tes"; + outputfile << var_header << std::endl; + } + + double tol = 1.e3; + double objective_value; + double common_coeff; + + double obj_wo_weight; // Objective function value without time weighting + double coeff_wo_weight; + for (int t = 0; t < params.n_periods; ++t) { + // Calculate objective value for time t + objective_value = 0.0; + obj_wo_weight = 0.0; + + common_coeff = params.delta * std::pow(params.time_weighting, t); + coeff_wo_weight = params.delta; + objective_value += common_coeff * params.sell_price[t] * vars.w_c[t]->solution_value(); + obj_wo_weight += coeff_wo_weight * params.sell_price[t] * vars.w_c[t]->solution_value(); + + if (config.is_heat_valued) { + objective_value += common_coeff * params.heat_sell_price[t] * vars.q_s[t]->solution_value(); + obj_wo_weight += coeff_wo_weight * params.heat_sell_price[t] * vars.q_s[t]->solution_value(); + } + + common_coeff = -params.delta * params.purchase_price[t] * (1. / std::pow(params.time_weighting, t)); + coeff_wo_weight = -params.delta * params.purchase_price[t]; + objective_value += common_coeff * vars.w_h[t]->solution_value(); + obj_wo_weight += coeff_wo_weight * vars.w_h[t]->solution_value(); + + common_coeff *= params.w_hp_startup; + coeff_wo_weight *= params.w_hp_startup; + objective_value += common_coeff * bin_vars.y_hsu[t]->solution_value(); + obj_wo_weight += coeff_wo_weight * bin_vars.y_hsu[t]->solution_value(); + + // Cost terms + common_coeff = -(1. / std::pow(params.time_weighting, t)); + coeff_wo_weight = -1.; + + objective_value += common_coeff * params.cycle_start_cost * bin_vars.y_csup[t]->solution_value(); + objective_value += common_coeff * params.cycle_ramping_cost * vars.q_delta_c[t]->solution_value(); + objective_value += common_coeff * params.heat_pump_start_cost * bin_vars.y_hsup[t]->solution_value(); + objective_value += common_coeff * params.heat_pump_ramp_cost * vars.w_delta_h[t]->solution_value(); + + obj_wo_weight += coeff_wo_weight * params.cycle_start_cost * bin_vars.y_csup[t]->solution_value(); + obj_wo_weight += coeff_wo_weight * params.cycle_ramping_cost * vars.q_delta_c[t]->solution_value(); + obj_wo_weight += coeff_wo_weight * params.heat_pump_start_cost * bin_vars.y_hsup[t]->solution_value(); + obj_wo_weight += coeff_wo_weight * params.heat_pump_ramp_cost * vars.w_delta_h[t]->solution_value(); + + outputfile << t + << ", " << objective_value + << ", " << obj_wo_weight + << ", " << params.sell_price[t] + << ", " << bin_vars.y_csup[t]->solution_value() + << ", " << bin_vars.y_csu[t]->solution_value() + << ", " << ((std::abs(vars.u_csu[t]->solution_value()) < tol) ? 0.0 : vars.u_csu[t]->solution_value()) + << ", " << bin_vars.y_c[t]->solution_value() + << ", " << ((std::abs(vars.w_c[t]->solution_value()) < tol) ? 0.0 : vars.w_c[t]->solution_value()) + << ", " << ((std::abs(vars.q_c[t]->solution_value()) < tol) ? 0.0 : vars.q_c[t]->solution_value()) + << ", " << ((std::abs(vars.q_delta_c[t]->solution_value()) < tol) ? 0.0 : vars.q_delta_c[t]->solution_value()) + << ", " << bin_vars.y_cgb[t]->solution_value() + << ", " << bin_vars.y_cge[t]->solution_value() + << ", " << ((std::abs(vars.s[t]->solution_value()) < tol) ? 0.0 : vars.s[t]->solution_value()) + << ", " << bin_vars.y_hsup[t]->solution_value() + << ", " << bin_vars.y_hsu[t]->solution_value() + << ", " << ((std::abs(vars.u_hsu[t]->solution_value()) < tol) ? 0.0 : vars.u_hsu[t]->solution_value()) + << ", " << bin_vars.y_h[t]->solution_value() + << ", " << ((std::abs(vars.w_h[t]->solution_value()) < tol) ? 0.0 : vars.w_h[t]->solution_value()) + << ", " << ((std::abs(vars.q_h[t]->solution_value()) < tol) ? 0.0 : vars.q_h[t]->solution_value()) + << ", " << ((std::abs(vars.w_delta_h[t]->solution_value()) < tol) ? 0.0 : vars.w_delta_h[t]->solution_value()) + << ", " << params.heat_sell_price[t] + << ", " << params.heat_demand[t] + << ", " << ((std::abs(vars.s_ot[t]->solution_value()) < tol) ? 0.0 : vars.s_ot[t]->solution_value()) + << ", " << ((std::abs(vars.q_s[t]->solution_value()) < tol) ? 0.0 : vars.q_s[t]->solution_value()) + << ", " << ((std::abs(vars.q_r[t]->solution_value()) < tol) ? 0.0 : vars.q_r[t]->solution_value()) + << ", " << ((std::abs(vars.q_tes[t]->solution_value()) < tol) ? 0.0 : vars.q_tes[t]->solution_value()) + << std::endl; + } + outputfile.close(); +} + +void ptes_chp_dispatch::create_startup_inventory_constraint(std::vector su_inv, std::vector su_binary, + double inv_roc, double init_su_inv, std::string name_pre) { + // Start-up inventory constraint for all time periods (0 to n_periods-1) + // General Form: su_inv[t] <= su_inv[t-1] + inv_roc * su_binary[t] + // if (t==0): su_inv[t] <= init_su_inv + inv_roc * su_binary[t] + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + if (t == 0) { + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), init_su_inv, name); + } + else { + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 0.0, name); + constraint->SetCoefficient(su_inv[t - 1], -1.0); + } + constraint->SetCoefficient(su_inv[t], 1.0); + constraint->SetCoefficient(su_binary[t], -inv_roc); + } +} + +void ptes_chp_dispatch::create_inventory_nonzero_constraint(std::vector su_inv, std::vector su_binary, + double su_inv_req, std::string name_pre) { + // Start-up inventory nonzero constraint for all time periods (0 to n_periods-1) + // General Form: su_inv[t] <= su_inv_req * su_binary[t] + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 0.0, name); + constraint->SetCoefficient(su_inv[t], 1.0); + constraint->SetCoefficient(su_binary[t], -su_inv_req); + } +} + +void ptes_chp_dispatch::create_operation_allowed_constraint(std::vector op_binary, std::vector su_inv, + double su_inv_req, int prev_op_state, std::string name_pre) { + // Operation allowing when start-up inventory is fulfilled or previously operating for all time periods (0 to n_periods-1) + // General Form: op_binary[t] <= su_inv[t] / su_inv_req + op_binary[t-1] + // if (t==0): op_binary[t] <= su_inv[t] / su_inv_req + prev_op_state + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + if (t == 0) { + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), su_inv_req * prev_op_state, name); + } + else { + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 0.0, name); + constraint->SetCoefficient(op_binary[t - 1], -su_inv_req); + } + constraint->SetCoefficient(op_binary[t], su_inv_req); + constraint->SetCoefficient(su_inv[t], -1.0); + } +} + +void ptes_chp_dispatch::create_startup_wait_constraint(std::vector su_binary, std::vector op_binary, + int prev_op_state, std::string name_pre) { + // Startup cannot be enabled after a time period where the device was operating for all time periods (0 to n_periods-1) + // General Form: su_binary[t] + op_binary[t-1] <= 1 + // if (t==0): su_binary[t] + prev_op_state <= 1 + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + if (t == 0) { + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 1.0 - prev_op_state, name); + // NOTE: for some reason range constraints are not working for Xpress... need to check the basic example + } + else { + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 1.0, name); + constraint->SetCoefficient(op_binary[t - 1], 1.0); + } + constraint->SetCoefficient(su_binary[t], 1.0); + } +} + +void ptes_chp_dispatch::create_minimum_operation_constraint(std::vector op_lvl, std::vector op_binary, + double min_limit, std::string name_pre) { + // Enforce minimum operation limit when system is operating for all time periods (0 to n_periods-1) + // General Form: op_lvl[t] >= min_limit * op_binary[t] + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(0.0, MPSolver::infinity(), name); + constraint->SetCoefficient(op_lvl[t], 1.0); + constraint->SetCoefficient(op_binary[t], -min_limit); + } +} + +void ptes_chp_dispatch::create_maximum_operation_wstartup_constraint(std::vector op_lvl, std::vector su_binary, std::vector op_binary, + double su_rate, double max_limit, std::string name_pre) { + // Enforce maximum operation limit when system is operating and if starting up for all time periods (0 to n_periods-1) + // General Form: op_lvl[t] + su_rate * su_binary[t] <= max_limit * op_binary[t] + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 0.0, name); + constraint->SetCoefficient(op_lvl[t], 1.0); + constraint->SetCoefficient(su_binary[t], su_rate); + constraint->SetCoefficient(op_binary[t], -max_limit); + } +} + +// Currently not being used +void ptes_chp_dispatch::create_maximum_operation_constraint(std::vector op_lvl, std::vector op_binary, + double max_limit, std::string name_pre) { + // Enforce maximum operation limit when system is operating for all time periods (0 to n_periods-1) + // General Form: op_lvl[t] <= max_limit * op_binary[t] + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 0.0, name); + constraint->SetCoefficient(op_lvl[t], 1.0); + constraint->SetCoefficient(op_binary[t], -max_limit); + } +} + +void ptes_chp_dispatch::create_linear_production_constraint(std::vector output, std::vector input, std::vector op_binary, + double slope, double intercept, std::vector amb_corr, std::string name_pre) { + // Model output production as a linear relationship of input for all time periods (0 to n_periods-1) + // General Form: output[t] = amb_corr[t] * ( slope * input[t] + intercept * op_binary[t]) + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(0.0, 0.0, name); + constraint->SetCoefficient(output[t], 1.0); + constraint->SetCoefficient(input[t], -amb_corr[t] * slope); + constraint->SetCoefficient(op_binary[t], -amb_corr[t] * intercept); + } +} + +void ptes_chp_dispatch::create_positive_ramping_constraint(std::vector ramping, std::vector op_lvl, + double prev_op_rate, std::string name_pre) { + // Calculates positive ramping for all time periods (0 to n_periods-1) + // General Form: ramping[t] >= op_lvl[t] - op_lvl[t-1] + // if (t==0): ramping[t] >= op_lvl[t] - prev_op_rate + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + if (t == 0) { + constraint = solver->MakeRowConstraint(-prev_op_rate, MPSolver::infinity(), name); + } + else { + constraint = solver->MakeRowConstraint(0.0, MPSolver::infinity(), name); + constraint->SetCoefficient(op_lvl[t - 1], 1.0); + } + constraint->SetCoefficient(ramping[t], 1.0); + constraint->SetCoefficient(op_lvl[t], -1.0); + } +} + +void ptes_chp_dispatch::create_startup_penalty_constraint(std::vector penalty_binary, std::vector su_binary, + double prev_su_state, std::string name_pre) { + // Enforces startup penalty for all time periods (0 to n_periods-1) + // General Form: penalty[t] >= su_binary[t] - su_binary[t-1] + // if (t==0): penalty_binary[t] >= su_binary[t] - prev_su_state + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + if (t == 0) { + constraint = solver->MakeRowConstraint(-prev_su_state, MPSolver::infinity(), name); + } + else { + constraint = solver->MakeRowConstraint(0.0, MPSolver::infinity(), name); + constraint->SetCoefficient(su_binary[t - 1], 1.0); + } + constraint->SetCoefficient(penalty_binary[t], 1.0); + constraint->SetCoefficient(su_binary[t], -1.0); + } +} + +void ptes_chp_dispatch::create_set_packing_constraint(std::vector binary1, std::vector binary2, std::string name_pre) { + // Enforces set packing constraint between two binaries variables for all time periods (0 to n_periods-1) + // General Form: binary1[t] + binary2[t] <= 1 + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 1.0, name); + constraint->SetCoefficient(binary1[t], 1.0); + constraint->SetCoefficient(binary2[t], 1.0); + } +} + +void ptes_chp_dispatch::create_min_up_down_logic_constraint(std::vector op_binary, std::vector up_binary, std::vector down_binary, + int prev_op_state, std::string name_pre) { + // Binary logic when switching state for tracking up- and down-time for all time periods (0 to n_periods-1) + // General Form: up_binary[t] - down_binary[t] = op_binary[t] - op_binary[t-1] + // if (t==0): up_binary[t] - down_binary[t] = op_binary[t] - prev_op_state + for (int t = 0; t < params.n_periods; t++) { // For all time periods + MPConstraint* constraint; + std::string name = name_pre + "[" + std::to_string(t) + "]"; + if (t == 0) { + constraint = solver->MakeRowConstraint(-prev_op_state, -prev_op_state, name); + } + else { + constraint = solver->MakeRowConstraint(0.0, 0.0, name); + constraint->SetCoefficient(op_binary[t - 1], 1.0); + } + constraint->SetCoefficient(up_binary[t], 1.0); + constraint->SetCoefficient(down_binary[t], -1.0); + constraint->SetCoefficient(op_binary[t], -1.0); + } +} + +void ptes_chp_dispatch::create_min_up_time_constraint(std::vector op_binary, std::vector up_binary, + int prev_op_state, min_up_down_params up_down_params, std::string name_pre) { + // Minimum up-time constraint + // General Form: sum{tp in Tau : 0 <= time_elapsed[t] - time_elapsed[tp] < min_up_time} up_binary[tp] <= op_binary[t] + // forall t in Tau : time_elapsed[t] > (min_up_time - init_up_time) * prev_op_state + for (int t = 0; t < params.n_periods; t++) { // For all time periods + if (up_down_params.time_elapsed.at(t) > (up_down_params.up_time_min - up_down_params.up_time0) * prev_op_state) { + MPConstraint* constraint; + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 0.0, name); + for (int tp = 0; tp < params.n_periods; tp++) { + double delta_time = up_down_params.time_elapsed.at(t) - up_down_params.time_elapsed.at(tp); + if ((delta_time >= 0) && (delta_time < up_down_params.up_time_min)) { + constraint->SetCoefficient(up_binary[tp], 1.0); + } + } + constraint->SetCoefficient(op_binary[t], -1.0); + } + } +} + +void ptes_chp_dispatch::create_min_down_time_constraint(std::vector op_binary, std::vector down_binary, + int prev_op_state, min_up_down_params up_down_params, std::string name_pre) { + // Minimum down-time constraint + // General Form: sum{tp in Tau : 0 <= time_elapsed[t] - time_elapsed[tp] < min_down_time} down_binary[tp] <= 1 - op_binary[t] + // forall t in Tau : time_elapsed[t] > (min_down_time - init_down_time) * (1 - prev_op_state) + for (int t = 0; t < params.n_periods; t++) { // For all time periods + if (up_down_params.time_elapsed.at(t) > (up_down_params.down_time_min - up_down_params.down_time0) * (1 - prev_op_state)) { + MPConstraint* constraint; + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 1.0, name); + for (int tp = 0; tp < params.n_periods; tp++) { + double delta_time = up_down_params.time_elapsed.at(t) - up_down_params.time_elapsed.at(tp); + if ((delta_time >= 0) && (delta_time < up_down_params.down_time_min)) { + constraint->SetCoefficient(down_binary[tp], 1.0); + } + } + constraint->SetCoefficient(op_binary[t], 1.0); + } + } +} + +void ptes_chp_dispatch::create_init_up_down_time_constraint(std::vector op_binary, int prev_op_state, + min_up_down_params up_down_params, std::string name_pre) { + // Initial minimum up- and down- time enforcement + // General Form: op_binary[t] = prev_op_state + // forall t in Tau : time_elapsed[t] <= max{ (min_up_time - init_up_time) * prev_op_state, + // (min_down_time - init_down_time) * (1 - prev_op_state)} + for (int t = 0; t < params.n_periods; t++) { + if (up_down_params.time_elapsed.at(t) <= std::max((up_down_params.up_time_min - up_down_params.up_time0) * prev_op_state, + (up_down_params.down_time_min - up_down_params.down_time0) * (1 - prev_op_state))) { + MPConstraint* constraint; + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(prev_op_state, prev_op_state, name); + constraint->SetCoefficient(op_binary[t], 1.0); + } + else break; + } +} + +void ptes_chp_dispatch::create_min_up_down_constraints(std::vector op_binary, std::vector up_binary, std::vector down_binary, + int prev_op_state, min_up_down_params up_down_params, std::string name_pre) { + // Binary logic when switching state + ptes_chp_dispatch::create_min_up_down_logic_constraint(op_binary, up_binary, down_binary, prev_op_state, name_pre + "binary_switch_logic"); + // minimum up-time constraint + ptes_chp_dispatch::create_min_up_time_constraint(op_binary, up_binary, prev_op_state, up_down_params, name_pre + "min_up_time"); + // minimum down-time constraint + ptes_chp_dispatch::create_min_down_time_constraint(op_binary, down_binary, prev_op_state, up_down_params, name_pre + "min_down_time"); + // initial minimum up- and down-time enforcement + ptes_chp_dispatch::create_init_up_down_time_constraint(op_binary, prev_op_state, up_down_params, name_pre + "min_up_ititial"); +} + diff --git a/shared/lib_ptes_chp_dispatch.h b/shared/lib_ptes_chp_dispatch.h new file mode 100644 index 0000000000..dc81ffaf78 --- /dev/null +++ b/shared/lib_ptes_chp_dispatch.h @@ -0,0 +1,476 @@ +#pragma once + +#include +#include "ortools/linear_solver/linear_solver.h" +using namespace operations_research; + +struct DispatchConfig { + bool is_offtaker_tes; // Does the heat off-taker have TES? Adds storage constraints for off-taker heat. + bool is_charge_heat_reject; // Does the PTES reject heat during charge? Enables rejected heat constraint during charging operations + bool is_discharge_heat_reject; // Does the PTES reject heat during discharge? Enables rejected heat constraint during discharging operations + bool is_heat_from_tes_allowed; // Can heat off-taker demand be met with PTES hot TES? + bool is_heat_demand_required; // Does the off-taker heat demand have to be met? Adds constraint that the heat demand must be met (can easily cause infeasibility) + bool is_heat_valued; // Is rejected heat valued? Heat to off-taker is valued in the objective function + + DispatchConfig() { + is_offtaker_tes = false; + is_charge_heat_reject = false; + is_discharge_heat_reject = false; + is_heat_from_tes_allowed = false; + is_heat_demand_required = false; + is_heat_valued = false; + }; +}; + +struct PtesDesign { + double cycle_cap; // [MWe] Cycle thermodynamic power + double cycle_eta; // [MWe/MWt] Cycle thermodynamic efficiency + double hp_cop; // [MWt/MWe] Heat Pump Coefficient of Performance + double tes_hrs; // [hours] Hours of storage + double tes_cap; // [MWht] Storage thermal capacity + double hp_cap; // [MWe] Heat pump thermodynamic power + + // initialize PTES design parameters + void init(double cycle_capacity /*MWe*/, double cycle_eff /*MWe/MWt*/, + double heatpump_cop /*MWt/MWe*/, double tes_duration /*hours*/) { + cycle_cap = cycle_capacity; + cycle_eta = cycle_eff; + hp_cop = heatpump_cop; + tes_hrs = tes_duration; + tes_cap = cycle_cap / cycle_eta * tes_hrs; // MWht Storage thermal capacity + hp_cap = (cycle_cap / cycle_eta) / hp_cop; // MWe Heat pump thermodynamic power + }; + +}; + +struct min_up_down_params { + std::vector time_elapsed; // [hr] Cumulative time elapsed at the end of period t + double down_time_min; // [hr] Minimum required power cycle down-time + double up_time_min; // [hr] Minimum required power cycle up-time + double down_time0; // [hr] Time that has passed since the cycle has been down before the initial time step + double up_time0; // [hr] Time that has passed since the cycle has been up before the initial time step + + min_up_down_params() { + down_time_min = std::numeric_limits::quiet_NaN(); + up_time_min = std::numeric_limits::quiet_NaN(); + down_time0 = std::numeric_limits::quiet_NaN(); + up_time0 = std::numeric_limits::quiet_NaN(); + } + + void clear() { + time_elapsed.clear(); + } + + void resize(int nt) { + time_elapsed.resize(nt, 0.); + } +}; + +struct PTES_CHP_Dispatch_Data { + // Parameters + int n_periods; // [-] Number of time steps within the time horizon + double time_weighting; // [-] Weighting factor that discounts future decisions over more imminent ones + double delta; // [hr] Duration of time period + + // Time-indexed Parameters + std::vector eta_amb; // [-] Cycle efficiency ambient temperature adjustment factor in period t + std::vector heat_sell_price; // [$/MWht] Heat sell price in period t + std::vector purchase_price; // [$/MWh] Electricity purchase price in period t + std::vector sell_price; // [$/MWh] Electricity sell price in period t + std::vector heat_demand; // [MWht] Off-taker heat demand in period t + + // Cost Parameters + double cycle_ramping_cost; // [$/MWt-change] Cost to change cycle thermal input level (ramping up) + double cycle_start_cost; // [$/start] Cost to start-up the power cycle + double heat_pump_ramp_cost; // [$/MWe-change] Cost to change heat pump electrical input level (ramping up) + double heat_pump_start_cost; // [$/start] Cost to start-up the heat pump + + // Power block (cycle) parameters + double e_pb_startup; // [MWht] Required energy expended to start the power cycle + double q_pb_max; // [MWt] Maximum operational thermal power input to the power cycle + double q_pb_min; // [MWt] Minimum operational thermal power input to the power cycle + double q_pb_startup; // [MWt] Thermal power input during power cycle start-up + double w_pb_max; // [MWe] Power cycle electric power rated capacity + double eta_p; // [MWe/MWt] Slope of linear approximation of power cycle performance curve + double eta_d; // [MWe/MWt] Cycle nominal efficiency + double q_rc; // [MWt] Thermal power rejected during cycle operations + + // initial conditions - Cycle + bool is_pb_starting0; // [-] Power block is starting at the initial time step + bool is_pb_operating0; // [-] Power block is operating at the initial time step + double q_pb0; // [MWt] Thermal power consumption in the cycle entering the initial time step + double e_pb_start0; // [-] Power block start energy consumed before initial time step + + min_up_down_params min_up_down_params; // Parameters required for minimum up- and down-time contraints + + // Heat pump parameters + double e_hp_startup; // [MWht] Required energy expended to start the heat pump + double w_hp_max; // [MWe] Maximum heat pump electric load + double w_hp_min; // [MWe] Minimum heat pump electric load + double w_hp_startup; // [MWe] Thermal power input during heat pump start-up + double q_hp_max; // [MWt] Heat pump maximimum operational thermal power output + double kappa_p; // [MWt/MWe] Slope of linear approximation of heat pump performance curve + double q_rh; // [MWt] Thermal power rejected during heat pump operations + + // initial conditions - Heat pump + bool is_hp_starting0; // [-] Heat pump is starting at the initial time step + bool is_hp_operating0; // [-] Heat pump is operating at the initial time step + double w_hp0; // [MWe] Electrical power consumption in the heat pump entering the initial time step + double e_hp_start0; // [-] Heat pump start energy consumed before initial time step + + // Thermal energy storage parameters + double e_tes_max; // [MWht] Thermal energy stroage capacity + double e_tes0; // [MWht] Current stored energy capacity + double e_loss; // [MWht] Heat loss from stroage + + // Heat off-taker parameters + double e_ot_max; // [MWht] Heat off-taker thermal energy storage capacity + double e_ot0; // [MWht] Current heat off-taker stored energy capacity + double e_ot_loss; // [MWht] Heat loss from stroage + double q_tes_max; // [MWt] Maximum heat rate that can be pulled from PTES storage + + PTES_CHP_Dispatch_Data() { + n_periods = 8760; + time_weighting = 0.99999; + delta = 1.0; + + cycle_ramping_cost = 0.63; // $/MW cap. form Kumar Gas - Aero Derivative CT (Typical Load Follows) + cycle_start_cost = 24.; // $/MW cap. from Kumar Gas - Aero Derivative CT (Warm Start) + heat_pump_ramp_cost = 0.63; //Assuming the same numbers for heat pump + heat_pump_start_cost = 24.; + + e_pb_startup = std::numeric_limits::quiet_NaN(); + q_pb_max = std::numeric_limits::quiet_NaN(); + q_pb_min = std::numeric_limits::quiet_NaN(); + q_pb_startup = std::numeric_limits::quiet_NaN(); + w_pb_max = std::numeric_limits::quiet_NaN(); + eta_p = std::numeric_limits::quiet_NaN(); + eta_d = std::numeric_limits::quiet_NaN(); + q_rc = std::numeric_limits::quiet_NaN(); + + is_pb_starting0 = false; + is_pb_operating0 = false; + q_pb0 = std::numeric_limits::quiet_NaN(); + e_pb_start0 = std::numeric_limits::quiet_NaN(); + + e_hp_startup = std::numeric_limits::quiet_NaN(); + w_hp_max = std::numeric_limits::quiet_NaN(); + w_hp_min = std::numeric_limits::quiet_NaN(); + w_hp_startup = std::numeric_limits::quiet_NaN(); + q_hp_max = std::numeric_limits::quiet_NaN(); + kappa_p = std::numeric_limits::quiet_NaN(); + q_rh = std::numeric_limits::quiet_NaN(); + + is_hp_starting0 = false; + is_hp_operating0 = false; + w_hp0 = std::numeric_limits::quiet_NaN(); + e_hp_start0 = std::numeric_limits::quiet_NaN(); + + e_tes_max = std::numeric_limits::quiet_NaN(); + e_tes0 = std::numeric_limits::quiet_NaN(); + e_loss = std::numeric_limits::quiet_NaN(); + + e_ot_max = std::numeric_limits::quiet_NaN(); + e_ot0 = std::numeric_limits::quiet_NaN(); + e_ot_loss = std::numeric_limits::quiet_NaN(); + q_tes_max = std::numeric_limits::quiet_NaN(); + } + + // Sets electricity sell and purchase prices as well as heat price + void setPrices(std::string sell_price_file, double average_price /*$/MWhe*/, double heat_price /*$/MWht*/); + + // Sets heat load based on file and multipler + void setHeatLoad(std::string heat_load_file, double multipler = 1.0 /*-*/); + + // Used to set a data vector via a csv file + static void set_data_by_file(std::vector& data, std::string filepath); + + void setDefaultAssumptions(PtesDesign design); + + void clear() + { + min_up_down_params.clear(); + eta_amb.clear(); + heat_sell_price.clear(); + purchase_price.clear(); + sell_price.clear(); + heat_demand.clear(); + } + + void resize(int nt) + { + min_up_down_params.resize(nt); + eta_amb.resize(nt, 0.); + heat_sell_price.resize(nt, 0.); + purchase_price.resize(nt, 0.); + sell_price.resize(nt, 0.); + heat_demand.resize(nt, 0.); + } + +}; + +struct PTES_CHP_Dispatch_Output { + std::vector q_c; // [MWt] Power cycle thermal power utilization in period t + std::vector q_delta_c; // [MWt] Change in power cycle thermal input at time t + std::vector q_h; // [MWt] Heat pump thermal power output in period t + std::vector q_r; // [MWt] Thermal power rejected in period t + std::vector q_s; // [MWt] Thermal power sold to heat off-taker in period t + std::vector s; // [MWht] Expected thermal energy storage charge state + std::vector s_ot; // [MWht] Expected off-taker thermal energy storage charge state + std::vector u_csu; // [MWht] Power cycle start-up energy inventory in period t + std::vector u_hsu; // [MWht] Heat pump start-up energy inventory in period t + std::vector w_c; // [MWe] Power cycle electricity generation in period t + std::vector w_delta_h; // [MWe] Change in heat pump electrical input in period t + std::vector w_h; // [MWe] Power cycle electricity generation in period t + + std::vector y_c; // [-] 1 if cycle is generating electric power in period t; 0 otherwise + std::vector y_cgb; // [-] 1 if cycle begins electric power generation in period t; 0 otherwise + std::vector y_cge; // [-] 1 if cycle stops electric power generation in period t; 0 otherwise + std::vector y_csu; // [-] 1 if cycle is starting up in period t; 0 otherwise + std::vector y_csup; // [-] 1 if cycle start-up cost is incurred in period t; 0 otherwise + std::vector y_h; // [-] 1 if heat pump is operating in period t; 0 otherwise + std::vector y_hsu; // [-] 1 if heat pump is starting up in period t; 0 otherwise + std::vector y_hsup; // [-] 1 if heat pump start-up cost is incurred in period t; 0 otherwise + + void clear() { + q_c.clear(); + q_delta_c.clear(); + q_h.clear(); + q_r.clear(); + q_s.clear(); + s.clear(); + s_ot.clear(); + u_csu.clear(); + u_hsu.clear(); + w_c.clear(); + w_delta_h.clear(); + w_h.clear(); + + y_c.clear(); + y_cgb.clear(); + y_cge.clear(); + y_csu.clear(); + y_csup.clear(); + y_h.clear(); + y_hsu.clear(); + y_hsup.clear(); + } + + void resize(int nt) { + q_c.resize(nt, 0.); + q_delta_c.resize(nt, 0.); + q_h.resize(nt, 0.); + q_r.resize(nt, 0.); + q_s.resize(nt, 0.); + s.resize(nt, 0.); + s_ot.resize(nt, 0.); + u_csu.resize(nt, 0.); + u_hsu.resize(nt, 0.); + w_c.resize(nt, 0.); + w_delta_h.resize(nt, 0.); + w_h.resize(nt, 0.); + + y_c.resize(nt, false); + y_cgb.resize(nt, false); + y_cge.resize(nt, false); + y_csu.resize(nt, false); + y_csup.resize(nt, false); + y_h.resize(nt, false); + y_hsu.resize(nt, false); + y_hsup.resize(nt, false); + } +}; + +class ptes_chp_dispatch +{ + struct ContinuousVariables { + std::vector q_c; // [units] description... + std::vector q_delta_c; + std::vector q_h; + std::vector q_r; + std::vector q_tes; + std::vector q_s; + std::vector s; + std::vector s_ot; + std::vector u_csu; + std::vector u_hsu; + std::vector w_c; + std::vector w_delta_h; + std::vector w_h; + + void Clear() { + q_c.clear(); + q_delta_c.clear(); + q_h.clear(); + q_r.clear(); + q_tes.clear(); + q_s.clear(); + s.clear(); + s_ot.clear(); + u_csu.clear(); + u_hsu.clear(); + w_c.clear(); + w_delta_h.clear(); + w_h.clear(); + } + } vars; + + struct BinaryVariables { + std::vector y_c; + std::vector y_cgb; + std::vector y_cge; + std::vector y_csu; + std::vector y_csup; + std::vector y_h; + std::vector y_hsu; + std::vector y_hsup; + + void Clear() { + y_c.clear(); + y_cgb.clear(); + y_cge.clear(); + y_csu.clear(); + y_csup.clear(); + y_h.clear(); + y_hsu.clear(); + y_hsup.clear(); + } + } bin_vars; + + MPObjective* objective; //const + + // Initialize solver + void initializeSolver(); + + // Create dispatch variables + void createVariables(); + + // Create dispatch constraints + void createConstraints(); + + // Create objective function + void createObjectiveFunction(); + + void printVariableValuesToConsole(absl::Duration wall_time); + + // Print model results to file + void printResultsFile(std::string filepath, bool append = false); + + // Update initial condtions + void updateInitialConditions(int init_t); + + +public: + std::unique_ptr solver; // TODO:: move back to private? + + DispatchConfig config; + + MPSolverParameters solver_params; + + PTES_CHP_Dispatch_Data params; + PTES_CHP_Dispatch_Output outputs; + + PtesDesign design; + + ptes_chp_dispatch(); + + // Create Solver + std::unique_ptr CreateSolver(const std::string& solver_id); + + // Declare dispatch formulation + double optimize(std::string resultsfilepath); + + // Do optimization with rolling horizon + double rollingHorizonoptimize(int opt_horizon, int roll_horizon, std::string resultsfilepath); + + // TODO:These functions should be inherited + + /*Start-up inventory constraint for all time periods(0 to nt - 1) + General Form: su_inv[t] <= su_inv[t-1] + inv_roc * su_binary[t] + if (t==0): su_inv[t] <= init_su_inv + inv_roc * su_binary[t]*/ + void create_startup_inventory_constraint(std::vector su_inv, std::vector su_binary, + double inv_roc, double init_su_inv = 0.0, std::string name_pre = ""); + + /* Start-up inventory nonzero constraint for all time periods(0 to nt - 1) + General Form: su_inv[t] <= su_inv_req * su_binary[t]*/ + void create_inventory_nonzero_constraint(std::vector su_inv, std::vector su_binary, + double su_inv_req, std::string name_pre = ""); + + /*Operation allowing when start - up inventory is fulfilled or previously operating for all time periods(0 to nt - 1) + General Form: op_binary[t] <= su_inv[t] / su_inv_req + op_binary[t-1] + if (t==0): op_binary[t] <= su_inv[t] / su_inv_req + prev_op_state */ + void create_operation_allowed_constraint(std::vector op_binary, std::vector su_inv, + double su_inv_req, int prev_op_state = 0.0, std::string name_pre = ""); + + /* Startup cannot be enabled after a time period where the device was operating for all time periods(0 to nt - 1) + General Form: su_binary[t] + op_binary[t-1] <= 1 + if (t==0): su_binary[t] + prev_op_state <= 1 */ + void create_startup_wait_constraint(std::vector su_binary, std::vector op_binary, + int prev_op_state = 0.0, std::string name_pre = ""); + + /* Enforce minimum operation limit when system is operating for all time periods(0 to nt - 1) + General Form: op_lvl[t] >= min_limit * op_binary[t] */ + void create_minimum_operation_constraint(std::vector op_lvl, std::vector op_binary, + double min_limit, std::string name_pre = ""); + + /* Enforce maximum operation limit when system is operatingand if starting up for all time periods(0 to nt - 1) + General Form: op_lvl[t] + su_rate * su_binary[t] <= max_limit * op_binary[t]*/ + void create_maximum_operation_wstartup_constraint(std::vector op_lvl, std::vector su_binary, std::vector op_binary, + double su_rate, double max_limit, std::string name_pre = ""); + + /* Enforce maximum operation limit when system is operating for all time periods (0 to n_periods-1) + General Form: op_lvl[t] <= max_limit * op_binary[t]*/ + void create_maximum_operation_constraint(std::vector op_lvl, std::vector op_binary, + double max_limit, std::string name_pre = ""); + + /* Model output production as a linear relationship of input for all time periods(0 to nt - 1) + General Form: output[t] = amb_corr[t] * ( slope * input[t] + intercept * op_binary[t])*/ + void create_linear_production_constraint(std::vector output, std::vector input, std::vector op_binary, + double slope, double intercept, std::vector amb_corr, std::string name_pre = ""); + + /* Calculates positive ramping for all time periods(0 to nt - 1) + General Form: ramping[t] >= op_lvl[t] - op_lvl[t-1] + if (t==0): ramping[t] >= op_lvl[t] - prev_op_rate*/ + void create_positive_ramping_constraint(std::vector ramping, std::vector op_lvl, + double prev_op_rate, std::string name_pre = ""); + + /* Enforces startup penalty for all time periods(0 to nt - 1) + General Form: penalty[t] >= su_binary[t] - su_binary[t-1] + if (t==0): penalty_binary[t] >= su_binary[t] - prev_su_state */ + void create_startup_penalty_constraint(std::vector penalty_binary, std::vector su_binary, + double prev_su_state = 0.0, std::string name_pre = ""); + + /*Enforces set packing constraint between two binaries variables for all time periods(0 to nt - 1) + General Form: binary1[t] + binary2[t] <= 1*/ + void create_set_packing_constraint(std::vector binary1, std::vector binary2, std::string name_pre = ""); + + /*Binary logic when switching state for tracking up - and down - time for all time periods(0 to nt - 1) + General Form: up_binary[t] - down_binary[t] = op_binary[t] - op_binary[t-1] + if (t==0): up_binary[t] - down_binary[t] = op_binary[t] - prev_op_state*/ + void create_min_up_down_logic_constraint(std::vector op_binary, std::vector up_binary, std::vector down_binary, + int prev_op_state, std::string name_pre = ""); + + /* Minimum up-time constraint + General Form: sum{tp in Tau : 0 <= time_elapsed[t] - time_elapsed[tp] < min_up_time} up_binary[tp] <= op_binary[t] + forall t in Tau : time_elapsed[t] > (min_up_time - init_up_time) * prev_op_state*/ + void create_min_up_time_constraint(std::vector op_binary, std::vector up_binary, + int prev_op_state, min_up_down_params params, std::string name_pre = ""); + + /* Minimum down-time constraint + General Form: sum{tp in Tau : 0 <= time_elapsed[t] - time_elapsed[tp] < min_down_time} down_binary[tp] <= 1 - op_binary[t] + forall t in Tau : time_elapsed[t] > (min_down_time - init_down_time) * (1 - prev_op_state)*/ + void create_min_down_time_constraint(std::vector op_binary, std::vector down_binary, + int prev_op_state, min_up_down_params params, std::string name_pre = ""); + + /* Initial minimum up- and down-time enforcement + General Form: op_binary[t] = prev_op_state + forall t in Tau : time_elapsed[t] <= max{ (min_up_time - init_up_time) * prev_op_state, + (min_down_time - init_down_time) * (1 - prev_op_state)}*/ + void create_init_up_down_time_constraint(std::vector op_binary, int prev_op_state, min_up_down_params params, std::string name_pre = ""); + + /* Creates minimum up- and down- constraints*/ + void create_min_up_down_constraints(std::vector op_binary, std::vector up_binary, std::vector down_binary, + int prev_op_state, min_up_down_params params, std::string name_pre = ""); + + +}; \ No newline at end of file diff --git a/splinter/CMakeLists.txt b/splinter/CMakeLists.txt index fba7f7e5d0..3e8b2abf51 100644 --- a/splinter/CMakeLists.txt +++ b/splinter/CMakeLists.txt @@ -4,20 +4,22 @@ # ##################################################################################################################### -include_directories(. ../ssc) +include_directories(. include src thirdparty/Eigen ../ssc) set(SPLINTER_SRC - bspline.cpp - bsplinebasis.cpp - bsplinebasis1d.cpp - bsplinebuilder.cpp - datapoint.cpp - datatable.cpp - function.cpp - knots.cpp - mykroneckerproduct.cpp - serializer.cpp - utilities.cpp) + src/bspline.cpp + src/bspline_basis.cpp + src/bspline_basis_1d.cpp + src/bspline_builders.cpp + src/bspline_utils.cpp + src/data_point.cpp + src/data_table.cpp + src/function.cpp + src/json_parser.cpp + src/knot_vector.cpp + src/knot_builders.cpp + src/kronecker_product.cpp + src/utilities.cpp) ##################################################################################################################### diff --git a/splinter/Geometry b/splinter/Geometry deleted file mode 100644 index efd9d4504c..0000000000 --- a/splinter/Geometry +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef EIGEN_GEOMETRY_MODULE_H -#define EIGEN_GEOMETRY_MODULE_H - -#include "Core" - -#include "src/Core/util/DisableStupidWarnings.h" - -#include "SVD" -#include "LU" -#include - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -/** \defgroup Geometry_Module Geometry module - * - * - * - * This module provides support for: - * - fixed-size homogeneous transformations - * - translation, scaling, 2D and 3D rotations - * - quaternions - * - \ref MatrixBase::cross() "cross product" - * - \ref MatrixBase::unitOrthogonal() "orthognal vector generation" - * - some linear components: parametrized-lines and hyperplanes - * - * \code - * #include - * \endcode - */ - -#include "src/Geometry/OrthoMethods.h" -#include "src/Geometry/EulerAngles.h" - -#if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS - #include "src/Geometry/Homogeneous.h" - #include "src/Geometry/RotationBase.h" - #include "src/Geometry/Rotation2D.h" - #include "src/Geometry/Quaternion.h" - #include "src/Geometry/AngleAxis.h" - #include "src/Geometry/Transform.h" - #include "src/Geometry/Translation.h" - #include "src/Geometry/Scaling.h" - #include "src/Geometry/Hyperplane.h" - #include "src/Geometry/ParametrizedLine.h" - #include "src/Geometry/AlignedBox.h" - #include "src/Geometry/Umeyama.h" - - #if defined EIGEN_VECTORIZE_SSE - #include "src/Geometry/arch/Geometry_SSE.h" - #endif -#endif - -#ifdef EIGEN2_SUPPORT -#include "src/Eigen2Support/Geometry/All.h" -#endif - -#include "src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN_GEOMETRY_MODULE_H -/* vim: set filetype=cpp et sw=2 ts=2 ai: */ - diff --git a/splinter/SVD b/splinter/SVD deleted file mode 100644 index fd310017ad..0000000000 --- a/splinter/SVD +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef EIGEN_SVD_MODULE_H -#define EIGEN_SVD_MODULE_H - -#include "QR" -#include "Householder" -#include "Jacobi" - -#include "src/Core/util/DisableStupidWarnings.h" - -/** \defgroup SVD_Module SVD module - * - * - * - * This module provides SVD decomposition for matrices (both real and complex). - * This decomposition is accessible via the following MatrixBase method: - * - MatrixBase::jacobiSvd() - * - * \code - * #include - * \endcode - */ - -#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 - -#include "src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN_SVD_MODULE_H -/* vim: set filetype=cpp et sw=2 ts=2 ai: */ diff --git a/splinter/bspline.cpp b/splinter/bspline.cpp deleted file mode 100644 index d4d62d2929..0000000000 --- a/splinter/bspline.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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/. -*/ -#include - -#include "bspline.h" -#include "bsplinebasis.h" -#include "mykroneckerproduct.h" -#include "unsupported/Eigen/KroneckerProduct" -#include "linearsolvers.h" -#include "serializer.h" -#include "utilities.h" - -namespace SPLINTER -{ - -BSpline::BSpline() - : Function(1) -{} - -BSpline::BSpline(unsigned int numVariables) - : Function(numVariables) -{} - -/* - * Constructors for multivariate B-spline using explicit data - */ -BSpline::BSpline(std::vector> knotVectors, std::vector basisDegrees) - : Function(knotVectors.size()), - basis(BSplineBasis(knotVectors, basisDegrees)), - coefficients(DenseVector::Zero(1)), - knotaverages(computeKnotAverages()) -{ - // Initialize coefficients to ones - setCoefficients(DenseVector::Ones(basis.getNumBasisFunctions())); - - checkControlPoints(); -} - -BSpline::BSpline(std::vector coefficients, std::vector> knotVectors, std::vector basisDegrees) - : BSpline(vectorToDenseVector(coefficients), knotVectors, basisDegrees) -{ -} - -BSpline::BSpline(DenseVector coefficients, std::vector> knotVectors, std::vector basisDegrees) - : Function(knotVectors.size()), - basis(BSplineBasis(knotVectors, basisDegrees)), - coefficients(coefficients), - knotaverages(computeKnotAverages()) -{ - setCoefficients(coefficients); - - checkControlPoints(); -} - -/* - * Construct from saved data - */ -BSpline::BSpline(const char *fileName) - : BSpline(std::string(fileName)) -{ -} - -BSpline::BSpline(const std::string &fileName) - : Function(1) -{ - load(fileName); -} - -/** - * Returns the function value at x - */ -double BSpline::eval(DenseVector x) const -{ - checkInput(x); - // NOTE: casting to DenseVector to allow accessing as res(0) - DenseVector res = coefficients.transpose()*evalBasis(x); - return res(0); -} - -/** - * Returns the (1 x numVariables) Jacobian evaluated at x - */ -DenseMatrix BSpline::evalJacobian(DenseVector x) const -{ - checkInput(x); - return coefficients.transpose()*evalBasisJacobian(x); -} - -/* - * Returns the Hessian evaluated at x. - * The Hessian is an n x n matrix, - * where n is the dimension of x. - */ -DenseMatrix BSpline::evalHessian(DenseVector x) const -{ - checkInput(x); - - #ifndef NDEBUG - if (!pointInDomain(x)) - throw Exception("BSpline::evalHessian: Evaluation at point outside domain."); - #endif // NDEBUG - - DenseMatrix H; - H.setZero(1,1); - DenseMatrix identity = DenseMatrix::Identity(numVariables, numVariables); - DenseMatrix caug = kroneckerProduct(identity, coefficients.transpose()); - DenseMatrix DB = basis.evalBasisHessian(x); - H = caug*DB; - - // Fill in upper triangular of Hessian - for (size_t i = 0; i < numVariables; ++i) - for (size_t j = i+1; j < numVariables; ++j) - H(i,j) = H(j,i); - - return H; -} - -// Evaluation of B-spline basis functions -SparseVector BSpline::evalBasis(DenseVector x) const -{ - #ifndef NDEBUG - if (!pointInDomain(x)) - throw Exception("BSpline::evalBasis: Evaluation at point outside domain."); - #endif // NDEBUG - - return basis.eval(x); -} - -SparseMatrix BSpline::evalBasisJacobian(DenseVector x) const -{ - #ifndef NDEBUG - if (!pointInDomain(x)) - throw Exception("BSpline::evalBasisJacobian: Evaluation at point outside domain."); - #endif // NDEBUG - - //SparseMatrix Bi = basis.evalBasisJacobian(x); // Sparse Jacobian implementation - //SparseMatrix Bi = basis.evalBasisJacobian2(x); // Sparse Jacobian implementation - DenseMatrix Bi = basis.evalBasisJacobianOld(x); // Old Jacobian implementation - - return Bi.sparseView(); -} - -std::vector BSpline::getNumBasisFunctionsPerVariable() const -{ - std::vector ret; - for (unsigned int i = 0; i < numVariables; i++) - ret.push_back(basis.getNumBasisFunctions(i)); - return ret; -} - -std::vector< std::vector > BSpline::getKnotVectors() const -{ - return basis.getKnotVectors(); -} - -std::vector BSpline::getBasisDegrees() const -{ - return basis.getBasisDegrees(); -} - -std::vector BSpline::getDomainUpperBound() const -{ - return basis.getSupportUpperBound(); -} - -std::vector BSpline::getDomainLowerBound() const -{ - return basis.getSupportLowerBound(); -} - -DenseMatrix BSpline::getControlPoints() const -{ - int nc = coefficients.size(); - DenseMatrix controlPoints(nc, numVariables + 1); - - controlPoints.block(0, 0, nc, numVariables) = knotaverages; - controlPoints.block(0, numVariables, nc, 1) = coefficients; - - return controlPoints; -} - -void BSpline::setCoefficients(const DenseVector &coefficients) -{ - if (coefficients.size() != getNumBasisFunctions()) - throw Exception("BSpline::setControlPoints: Incompatible size of coefficient vector."); - - this->coefficients = coefficients; - checkControlPoints(); -} - -void BSpline::setControlPoints(const DenseMatrix &controlPoints) -{ - if (controlPoints.cols() != numVariables + 1) - throw Exception("BSpline::setControlPoints: Incompatible size of control point matrix."); - - int nc = controlPoints.rows(); - - knotaverages = controlPoints.block(0, 0, nc, numVariables); - coefficients = controlPoints.block(0, numVariables, nc, 1); - - checkControlPoints(); -} - -void BSpline::updateControlPoints(const DenseMatrix &A) -{ - if (A.cols() != coefficients.rows() || A.cols() != knotaverages.rows()) - throw Exception("BSpline::updateControlPoints: Incompatible size of linear transformation matrix."); - coefficients = A*coefficients; - knotaverages = A*knotaverages; -} - -void BSpline::checkControlPoints() const -{ - if (coefficients.rows() != knotaverages.rows()) - throw Exception("BSpline::checkControlPoints: Inconsistent size of coefficients and knot averages matrices."); - if (knotaverages.cols() != numVariables) - throw Exception("BSpline::checkControlPoints: Inconsistent size of knot averages matrix."); -} - -bool BSpline::pointInDomain(DenseVector x) const -{ - return basis.insideSupport(x); -} - -void BSpline::reduceSupport(std::vector lb, std::vector ub, bool doRegularizeKnotVectors) -{ - if (lb.size() != numVariables || ub.size() != numVariables) - throw Exception("BSpline::reduceSupport: Inconsistent vector sizes!"); - - std::vector sl = basis.getSupportLowerBound(); - std::vector su = basis.getSupportUpperBound(); - - for (unsigned int dim = 0; dim < numVariables; dim++) - { - // Check if new domain is empty - if (ub.at(dim) <= lb.at(dim) || lb.at(dim) >= su.at(dim) || ub.at(dim) <= sl.at(dim)) - throw Exception("BSpline::reduceSupport: Cannot reduce B-spline domain to empty set!"); - - // Check if new domain is a strict subset - if (su.at(dim) < ub.at(dim) || sl.at(dim) > lb.at(dim)) - throw Exception("BSpline::reduceSupport: Cannot expand B-spline domain!"); - - // Tightest possible - sl.at(dim) = lb.at(dim); - su.at(dim) = ub.at(dim); - } - - if (doRegularizeKnotVectors) - { - regularizeKnotVectors(sl, su); - } - - // Remove knots and control points that are unsupported with the new bounds - if (!removeUnsupportedBasisFunctions(sl, su)) - { - throw Exception("BSpline::reduceSupport: Failed to remove unsupported basis functions!"); - } -} - -void BSpline::globalKnotRefinement() -{ - // Compute knot insertion matrix - SparseMatrix A = basis.refineKnots(); - - // Update control points - updateControlPoints(A); -} - -void BSpline::localKnotRefinement(DenseVector x) -{ - // Compute knot insertion matrix - SparseMatrix A = basis.refineKnotsLocally(x); - - // Update control points - updateControlPoints(A); -} - -void BSpline::decomposeToBezierForm() -{ - // Compute knot insertion matrix - SparseMatrix A = basis.decomposeToBezierForm(); - - // Update control points - updateControlPoints(A); -} - -// Computes knot averages: assumes that basis is initialized! -DenseMatrix BSpline::computeKnotAverages() const -{ - // Calculate knot averages for each knot vector - std::vector mu_vectors; - for (unsigned int i = 0; i < numVariables; i++) - { - std::vector knots = basis.getKnotVector(i); - DenseVector mu = DenseVector::Zero(basis.getNumBasisFunctions(i)); - - for (unsigned int j = 0; j < basis.getNumBasisFunctions(i); j++) - { - double knotAvg = 0; - for (unsigned int k = j+1; k <= j+basis.getBasisDegree(i); k++) - { - knotAvg += knots.at(k); - } - mu(j) = knotAvg/basis.getBasisDegree(i); - } - mu_vectors.push_back(mu); - } - - // Calculate vectors of ones (with same length as corresponding knot average vector) - std::vector knotOnes; - for (unsigned int i = 0; i < numVariables; i++) - knotOnes.push_back(DenseVector::Ones(mu_vectors.at(i).rows())); - - // Fill knot average matrix one column at the time - DenseMatrix knot_averages = DenseMatrix::Zero(basis.getNumBasisFunctions(), numVariables); - - for (unsigned int i = 0; i < numVariables; i++) - { - DenseMatrix mu_ext(1,1); mu_ext(0,0) = 1; - for (unsigned int j = 0; j < numVariables; j++) - { - DenseMatrix temp = mu_ext; - if (i == j) - mu_ext = Eigen::kroneckerProduct(temp, mu_vectors.at(j)); - else - mu_ext = Eigen::kroneckerProduct(temp, knotOnes.at(j)); - } - if (mu_ext.rows() != basis.getNumBasisFunctions()) - throw Exception("BSpline::computeKnotAverages: Incompatible size of knot average matrix."); - knot_averages.block(0, i, basis.getNumBasisFunctions(), 1) = mu_ext; - } - - return knot_averages; -} - -void BSpline::insertKnots(double tau, unsigned int dim, unsigned int multiplicity) -{ - // Insert knots and compute knot insertion matrix - SparseMatrix A = basis.insertKnots(tau, dim, multiplicity); - - // Update control points - updateControlPoints(A); -} - -void BSpline::regularizeKnotVectors(std::vector &lb, std::vector &ub) -{ - // Add and remove controlpoints and knots to make the b-spline p-regular with support [lb, ub] - if (!(lb.size() == numVariables && ub.size() == numVariables)) - throw Exception("BSpline::regularizeKnotVectors: Inconsistent vector sizes."); - - for (unsigned int dim = 0; dim < numVariables; dim++) - { - unsigned int multiplicityTarget = basis.getBasisDegree(dim) + 1; - - // Inserting many knots at the time (to save number of B-spline coefficient calculations) - // NOTE: This method generates knot insertion matrices with more nonzero elements than - // the method that inserts one knot at the time. This causes the preallocation of - // kronecker product matrices to become too small and the speed deteriorates drastically - // in higher dimensions because reallocation is necessary. This can be prevented by - // precomputing the number of nonzeros when preallocating memory (see myKroneckerProduct). - int numKnotsLB = multiplicityTarget - basis.getKnotMultiplicity(dim, lb.at(dim)); - if (numKnotsLB > 0) - { - insertKnots(lb.at(dim), dim, numKnotsLB); - } - - int numKnotsUB = multiplicityTarget - basis.getKnotMultiplicity(dim, ub.at(dim)); - if (numKnotsUB > 0) - { - insertKnots(ub.at(dim), dim, numKnotsUB); - } - } -} - -bool BSpline::removeUnsupportedBasisFunctions(std::vector &lb, std::vector &ub) -{ - if (lb.size() != numVariables || ub.size() != numVariables) - throw Exception("BSpline::removeUnsupportedBasisFunctions: Incompatible dimension of domain bounds."); - - SparseMatrix A = basis.reduceSupport(lb, ub); - - if (coefficients.size() != A.rows()) - return false; - - // Remove unsupported control points (basis functions) - updateControlPoints(A.transpose()); - - return true; -} - -void BSpline::save(const std::string &fileName) const -{ - Serializer s; - s.serialize(*this); - s.saveToFile(fileName); -} - -void BSpline::load(const std::string &fileName) -{ - Serializer s(fileName); - s.deserialize(*this); -} - -std::string BSpline::getDescription() const -{ - std::string description("BSpline of degree"); - auto degrees = getBasisDegrees(); - // See if all degrees are the same. - bool equal = true; - for (size_t i = 1; i < degrees.size(); ++i) - { - equal = equal && (degrees.at(i) == degrees.at(i-1)); - } - - if(equal) - { - description.append(" "); - description.append(std::to_string(degrees.at(0))); - } - else - { - description.append("s ("); - for (size_t i = 0; i < degrees.size(); ++i) - { - description.append(std::to_string(degrees.at(i))); - if (i + 1 < degrees.size()) - { - description.append(", "); - } - } - description.append(")"); - } - - return description; -} - -} // namespace SPLINTER diff --git a/splinter/bspline.h b/splinter/bspline.h deleted file mode 100644 index eb72dc8000..0000000000 --- a/splinter/bspline.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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 SPLINTER_BSPLINE_H -#define SPLINTER_BSPLINE_H - -#include "function.h" -#include "bsplinebasis.h" - -namespace SPLINTER -{ - -/** - * Class that implements the multivariate tensor product B-spline - */ -class SPLINTER_API BSpline : public Function -{ -public: - /** - * Builder class for construction by regression - * Implemented in BSplineBuilder.* - */ - class Builder; - enum class Smoothing; - enum class KnotSpacing; - - BSpline(unsigned int numVariables); - - /** - * Construct B-spline from knot vectors, coefficients, and basis degrees - */ - BSpline(std::vector< std::vector > knotVectors, std::vector basisDegrees); - BSpline(std::vector coefficients, std::vector< std::vector > knotVectors, std::vector basisDegrees); - BSpline(DenseVector coefficients, std::vector< std::vector > knotVectors, std::vector basisDegrees); - - /** - * Construct B-spline from file - */ - BSpline(const char *fileName); - BSpline(const std::string &fileName); - - virtual BSpline* clone() const { return new BSpline(*this); } - - /** - * Evaluation of B-spline - */ - - // Avoid name hiding - using Function::eval; - using Function::evalJacobian; - using Function::evalHessian; - - // Evaluation of B-spline - double eval(DenseVector x) const override; - DenseMatrix evalJacobian(DenseVector x) const override; - DenseMatrix evalHessian(DenseVector x) const override; - - // Evaluation of B-spline basis functions - SparseVector evalBasis(DenseVector x) const; - SparseMatrix evalBasisJacobian(DenseVector x) const; - - /** - * Getters - */ - DenseVector getCoefficients() - { - return coefficients; - } - - unsigned int getNumCoefficients() const - { - return (unsigned int)coefficients.size(); - } - - unsigned int getNumControlPoints() const - { - return (unsigned int)coefficients.size(); - } - - std::vector getNumBasisFunctionsPerVariable() const; - - unsigned int getNumBasisFunctions() const - { - return basis.getNumBasisFunctions(); - } - - DenseMatrix getControlPoints() const; - std::vector< std::vector> getKnotVectors() const; - std::vector getBasisDegrees() const; - std::vector getDomainUpperBound() const; - std::vector getDomainLowerBound() const; - - /** - * Setters - */ - void setCoefficients(const DenseVector &coefficients); - void setControlPoints(const DenseMatrix &controlPoints); - void checkControlPoints() const; - - // Linear transformation of control points (B-spline has affine invariance) - void updateControlPoints(const DenseMatrix &A); - - // Reduce support of B-spline - void reduceSupport(std::vector lb, std::vector ub, bool doRegularizeKnotVectors = true); - - // Perform global knot refinement - void globalKnotRefinement(); // All knots in one shabang - - // Perform a local knot refinement at x - void localKnotRefinement(DenseVector x); - - // Decompose B-spline to Bezier form - void decomposeToBezierForm(); - - // Insert a knot until desired knot multiplicity is obtained - void insertKnots(double tau, unsigned int dim, unsigned int multiplicity = 1); - - void save(const std::string &fileName) const override; - - std::string getDescription() const override; - BSpline(); - -protected: - - BSplineBasis basis; - - /* - * The control point matrix is P = (knotaverages, coefficients) in R^(m x n), - * where m = numBasisFunctions and n = numVariables + 1. Each row in P is a control point. - */ - DenseVector coefficients; - DenseMatrix knotaverages; - - // Control point computations - DenseMatrix computeKnotAverages() const; - -private: - // Domain reduction - void regularizeKnotVectors(std::vector &lb, std::vector &ub); - bool removeUnsupportedBasisFunctions(std::vector &lb, std::vector &ub); - - // Helper functions - bool pointInDomain(DenseVector x) const; - - void load(const std::string &fileName) override; - - friend class Serializer; - friend bool operator==(const BSpline &lhs, const BSpline &rhs); -}; - -} // namespace SPLINTER - -#endif // SPLINTER_BSPLINE_H diff --git a/splinter/bsplinebasis.cpp b/splinter/bsplinebasis.cpp deleted file mode 100644 index c90bbd6ea9..0000000000 --- a/splinter/bsplinebasis.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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/. -*/ - -#include "bsplinebasis.h" -#include "mykroneckerproduct.h" -#include "unsupported/Eigen/KroneckerProduct" - -#include - -namespace SPLINTER -{ - -BSplineBasis::BSplineBasis() -{ -} - -BSplineBasis::BSplineBasis(std::vector< std::vector > &knotVectors, std::vector basisDegrees) - : numVariables(knotVectors.size()) -{ - if (knotVectors.size() != basisDegrees.size()) - throw Exception("BSplineBasis::BSplineBasis: Incompatible sizes. Number of knot vectors is not equal to size of degree vector."); - - // Set univariate bases - bases.clear(); - for (unsigned int i = 0; i < numVariables; i++) - { - bases.push_back(BSplineBasis1D(knotVectors.at(i), basisDegrees.at(i))); - - // Adjust target number of basis functions used in e.g. refinement - if (numVariables > 2) - { - // One extra knot is allowed - bases.at(i).setNumBasisFunctionsTarget((basisDegrees.at(i)+1)+1); // Minimum degree+1 - } - } -} - -SparseVector BSplineBasis::eval(const DenseVector &x) const -{ - // Evaluate basisfunctions for each variable i and compute the tensor product of the function values - std::vector basisFunctionValues; - - for (int var = 0; var < x.size(); var++) - basisFunctionValues.push_back(bases.at(var).eval(x(var))); - - return kroneckerProductVectors(basisFunctionValues); -} - -// Old implementation of Jacobian -DenseMatrix BSplineBasis::evalBasisJacobianOld(DenseVector &x) const -{ - // Jacobian basis matrix - DenseMatrix J; J.setZero(getNumBasisFunctions(), numVariables); - - // Calculate partial derivatives - for (unsigned int i = 0; i < numVariables; i++) - { - // One column in basis jacobian - DenseVector bi; bi.setOnes(1); - for (unsigned int j = 0; j < numVariables; j++) - { - DenseVector temp = bi; - DenseVector xi; - if (j == i) - { - // Differentiated basis - xi = bases.at(j).evalFirstDerivative(x(j)); - } - else - { - // Normal basis - xi = bases.at(j).eval(x(j)); - } - - bi = kroneckerProduct(temp, xi); - } - - // Fill out column - J.block(0,i,bi.rows(),1) = bi.block(0,0,bi.rows(),1); - } - - return J; -} - -// NOTE: does not pass tests -SparseMatrix BSplineBasis::evalBasisJacobian(DenseVector &x) const -{ - // Jacobian basis matrix - SparseMatrix J(getNumBasisFunctions(), numVariables); - //J.setZero(numBasisFunctions(), numInputs); - - // Calculate partial derivatives - for (unsigned int i = 0; i < numVariables; ++i) - { - // One column in basis jacobian - std::vector values(numVariables); - - for (unsigned int j = 0; j < numVariables; ++j) - { - if (j == i) - { - // Differentiated basis - values.at(j) = bases.at(j).evalDerivative(x(j), 1); - } - else - { - // Normal basis - values.at(j) = bases.at(j).eval(x(j)); - } - } - - SparseVector Ji = kroneckerProductVectors(values); - - // Fill out column - for (int k = 0; k < Ji.outerSize(); ++k) - for (SparseMatrix::InnerIterator it(Ji,k); it; ++it) - { - if (it.value() != 0) - J.insert(it.row(),i) = it.value(); - } - //J.block(0,i,Ji.rows(),1) = bi.block(0,0,Ji.rows(),1); - } - - J.makeCompressed(); - - return J; -} - -SparseMatrix BSplineBasis::evalBasisJacobian2(DenseVector &x) const -{ - // Jacobian basis matrix - SparseMatrix J(getNumBasisFunctions(), numVariables); - - // Evaluate B-spline basis functions before looping - std::vector funcValues(numVariables); - std::vector gradValues(numVariables); - - for (unsigned int i = 0; i < numVariables; ++i) - { - funcValues[i] = bases.at(i).eval(x(i)); - gradValues[i] = bases.at(i).evalFirstDerivative(x(i)); - } - - // Calculate partial derivatives - for (unsigned int i = 0; i < numVariables; i++) - { - std::vector values(numVariables); - - for (unsigned int j = 0; j < numVariables; j++) - { - if (j == i) - values.at(j) = gradValues.at(j); // Differentiated basis - else - values.at(j) = funcValues.at(j); // Normal basis - } - - SparseVector Ji = kroneckerProductVectors(values); - - // Fill out column - for (SparseVector::InnerIterator it(Ji); it; ++it) - J.insert(it.row(),i) = it.value(); - } - - return J; -} - -SparseMatrix BSplineBasis::evalBasisHessian(DenseVector &x) const -{ - // Hessian basis matrix - /* Hij = B1 x ... x DBi x ... x DBj x ... x Bn - * (Hii = B1 x ... x DDBi x ... x Bn) - * Where B are basis functions evaluated at x, - * DB are the derivative of the basis functions, - * and x is the kronecker product. - * Hij is in R^(numBasisFunctions x 1) - * so that basis hessian H is in R^(numBasisFunctions*numInputs x numInputs) - * The real B-spline Hessian is calculated as (c^T x 1^(numInputs x 1))*H - */ - SparseMatrix H(getNumBasisFunctions()*numVariables, numVariables); - //H.setZero(numBasisFunctions()*numInputs, numInputs); - - // Calculate partial derivatives - // Utilizing that Hessian is symmetric - // Filling out lower left triangular - for (unsigned int i = 0; i < numVariables; i++) // row - { - for (unsigned int j = 0; j <= i; j++) // col - { - // One column in basis jacobian - SparseMatrix Hi(1,1); - Hi.insert(0,0) = 1; - - for (unsigned int k = 0; k < numVariables; k++) - { - SparseMatrix temp = Hi; - SparseMatrix Bk; - if (i == j && k == i) - { - // Diagonal element - Bk = bases.at(k).evalDerivative(x(k), 2); - } - else if (k == i || k == j) - { - Bk = bases.at(k).evalDerivative(x(k), 1); - } - else - { - Bk = bases.at(k).eval(x(k)); - } - Hi = kroneckerProduct(temp, Bk); - } - - // Fill out column - for (int k = 0; k < Hi.outerSize(); ++k) - for (SparseMatrix::InnerIterator it(Hi,k); it; ++it) - { - if (it.value() != 0) - { - int row = i*getNumBasisFunctions()+it.row(); - int col = j; - H.insert(row,col) = it.value(); - } - } - } - } - - H.makeCompressed(); - - return H; -} - -SparseMatrix BSplineBasis::insertKnots(double tau, unsigned int dim, unsigned int multiplicity) -{ - SparseMatrix A(1,1); -// A.resize(1,1); - A.insert(0,0) = 1; - - // Calculate multivariate knot insertion matrix - for (unsigned int i = 0; i < numVariables; i++) - { - SparseMatrix temp = A; - SparseMatrix Ai; - - if (i == dim) - { - // Build knot insertion matrix - Ai = bases.at(i).insertKnots(tau, multiplicity); - } - else - { - // No insertion - identity matrix - int m = bases.at(i).getNumBasisFunctions(); - Ai.resize(m,m); - Ai.setIdentity(); - } - - //A = kroneckerProduct(temp, Ai); - A = myKroneckerProduct(temp, Ai); - } - - A.makeCompressed(); - - return A; -} - -SparseMatrix BSplineBasis::refineKnots() -{ - SparseMatrix A(1,1); - A.insert(0,0) = 1; - - for (unsigned int i = 0; i < numVariables; i++) - { - SparseMatrix temp = A; - SparseMatrix Ai = bases.at(i).refineKnots(); - - //A = kroneckerProduct(temp, Ai); - A = myKroneckerProduct(temp, Ai); - } - - A.makeCompressed(); - - return A; -} - -SparseMatrix BSplineBasis::refineKnotsLocally(DenseVector x) -{ - SparseMatrix A(1,1); - A.insert(0,0) = 1; - - for (unsigned int i = 0; i < numVariables; i++) - { - SparseMatrix temp = A; - SparseMatrix Ai = bases.at(i).refineKnotsLocally(x(i)); - - //A = kroneckerProduct(temp, Ai); - A = myKroneckerProduct(temp, Ai); - } - - A.makeCompressed(); - - return A; -} - -SparseMatrix BSplineBasis::decomposeToBezierForm() -{ - SparseMatrix A(1,1); - A.insert(0,0) = 1; - - for (unsigned int i = 0; i < numVariables; i++) - { - SparseMatrix temp = A; - SparseMatrix Ai = bases.at(i).decomposeToBezierForm(); - - //A = kroneckerProduct(temp, Ai); - A = myKroneckerProduct(temp, Ai); - } - - A.makeCompressed(); - - return A; -} - -SparseMatrix BSplineBasis::reduceSupport(std::vector& lb, std::vector& ub) -{ - if (lb.size() != ub.size() || lb.size() != numVariables) - throw Exception("BSplineBasis::reduceSupport: Incompatible dimension of domain bounds."); - - SparseMatrix A(1,1); - A.insert(0,0) = 1; - - for (unsigned int i = 0; i < numVariables; i++) - { - SparseMatrix temp = A; - SparseMatrix Ai; - - Ai = bases.at(i).reduceSupport(lb.at(i), ub.at(i)); - - //A = kroneckerProduct(temp, Ai); - A = myKroneckerProduct(temp, Ai); - } - - A.makeCompressed(); - - return A; -} - -std::vector BSplineBasis::getBasisDegrees() const -{ - std::vector degrees; - for (const auto& basis : bases) - degrees.push_back(basis.getBasisDegree()); - return degrees; -} - -unsigned int BSplineBasis::getBasisDegree(unsigned int dim) const -{ - return bases.at(dim).getBasisDegree(); -} - -unsigned int BSplineBasis::getNumBasisFunctions(unsigned int dim) const -{ - return bases.at(dim).getNumBasisFunctions(); -} - -unsigned int BSplineBasis::getNumBasisFunctions() const -{ - unsigned int prod = 1; - for (unsigned int dim = 0; dim < numVariables; dim++) - { - prod *= bases.at(dim).getNumBasisFunctions(); - } - return prod; -} - -BSplineBasis1D BSplineBasis::getSingleBasis(int dim) -{ - return bases.at(dim); -} - -std::vector BSplineBasis::getKnotVector(int dim) const -{ - return bases.at(dim).getKnotVector(); -} - -std::vector< std::vector > BSplineBasis::getKnotVectors() const -{ - std::vector< std::vector > knots; - for (unsigned int i = 0; i < numVariables; i++) - knots.push_back(bases.at(i).getKnotVector()); - return knots; -} - -unsigned int BSplineBasis::getKnotMultiplicity(unsigned int dim, double tau) const -{ - return bases.at(dim).knotMultiplicity(tau); -} - -double BSplineBasis::getKnotValue(int dim, int index) const -{ - return bases.at(dim).getKnotValue(index); -} - -unsigned int BSplineBasis::getLargestKnotInterval(unsigned int dim) const -{ - return bases.at(dim).indexLongestInterval(); -} - -std::vector BSplineBasis::getNumBasisFunctionsTarget() const -{ - std::vector ret; - for (unsigned int dim = 0; dim < numVariables; dim++) - { - ret.push_back(bases.at(dim).getNumBasisFunctionsTarget() ); - } - return ret; -} - -int BSplineBasis::supportedPrInterval() const -{ - int ret = 1; - for (unsigned int dim = 0; dim < numVariables; dim++) - { - ret *= (bases.at(dim).getBasisDegree() + 1); - } - return ret; -} - -bool BSplineBasis::insideSupport(DenseVector &x) const -{ - for (unsigned int dim = 0; dim < numVariables; dim++) - { - if (!bases.at(dim).insideSupport(x(dim))) - { - return false; - } - } - return true; -} - -std::vector BSplineBasis::getSupportLowerBound() const -{ - std::vector lb; - for (unsigned int dim = 0; dim < numVariables; dim++) - { - std::vector knots = bases.at(dim).getKnotVector(); - lb.push_back(knots.front()); - } - return lb; -} - -std::vector BSplineBasis::getSupportUpperBound() const -{ - std::vector ub; - for (unsigned int dim = 0; dim < numVariables; dim++) - { - std::vector knots = bases.at(dim).getKnotVector(); - ub.push_back(knots.back()); - } - return ub; -} - -} // namespace SPLINTER diff --git a/splinter/bsplinebasis.h b/splinter/bsplinebasis.h deleted file mode 100644 index 039c8d44fb..0000000000 --- a/splinter/bsplinebasis.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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 SPLINTER_BSPLINEBASIS_H -#define SPLINTER_BSPLINEBASIS_H - -#include "definitions.h" -#include "bsplinebasis1d.h" - -namespace SPLINTER -{ - -class BSplineBasis -{ -public: - BSplineBasis(); - BSplineBasis(std::vector> &knotVectors, std::vector basisDegrees); - - // Evaluation - SparseVector eval(const DenseVector &x) const; - DenseMatrix evalBasisJacobianOld(DenseVector &x) const; // Depricated - SparseMatrix evalBasisJacobian(DenseVector &x) const; - SparseMatrix evalBasisJacobian2(DenseVector &x) const; // A bit slower than evaBasisJacobianOld() - SparseMatrix evalBasisHessian(DenseVector &x) const; - - // Knot vector manipulation - SparseMatrix refineKnots(); - SparseMatrix refineKnotsLocally(DenseVector x); - SparseMatrix decomposeToBezierForm(); - SparseMatrix insertKnots(double tau, unsigned int dim, unsigned int multiplicity = 1); - - // Getters - BSplineBasis1D getSingleBasis(int dim); - std::vector< std::vector > getKnotVectors() const; - std::vector getKnotVector(int dim) const; - - std::vector getBasisDegrees() const; - unsigned int getBasisDegree(unsigned int dim) const; - unsigned int getNumBasisFunctions() const; - unsigned int getNumBasisFunctions(unsigned int dim) const; - std::vector getNumBasisFunctionsTarget() const; - - double getKnotValue(int dim, int index) const; - unsigned int getKnotMultiplicity(unsigned int dim, double tau) const; - unsigned int getLargestKnotInterval(unsigned int dim) const; - - int supportedPrInterval() const; - - bool insideSupport(DenseVector &x) const; - std::vector getSupportLowerBound() const; - std::vector getSupportUpperBound() const; - - // Support related - SparseMatrix reduceSupport(std::vector& lb, std::vector& ub); - -private: - std::vector bases; - unsigned int numVariables; - - friend class Serializer; - friend bool operator==(const BSplineBasis &lhs, const BSplineBasis &rhs); -}; - -} // namespace SPLINTER - -#endif // SPLINTER_BSPLINEBASIS_H diff --git a/splinter/bsplinebasis1d.cpp b/splinter/bsplinebasis1d.cpp deleted file mode 100644 index 2494d6b711..0000000000 --- a/splinter/bsplinebasis1d.cpp +++ /dev/null @@ -1,607 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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/. -*/ -#include -#include - -#include "bsplinebasis1d.h" -#include "knots.h" -#include "utilities.h" - -namespace SPLINTER -{ - -BSplineBasis1D::BSplineBasis1D() -{ -} - -BSplineBasis1D::BSplineBasis1D(const std::vector &knots, unsigned int degree) - : degree(degree), - knots(knots), - targetNumBasisfunctions((degree+1)+2*degree+1) // Minimum p+1 -{ -// if (degree <= 0) -// throw Exception("BSplineBasis1D::BSplineBasis1D: Cannot create B-spline basis functions of degree <= 0."); - - if (!isKnotVectorRegular(knots, degree)) - throw Exception("BSplineBasis1D::BSplineBasis1D: Knot vector is not regular."); -} - -SparseVector BSplineBasis1D::eval(double x) const -{ - SparseVector values(getNumBasisFunctions()); - - if (!insideSupport(x)) - return values; - - supportHack(x); - - std::vector indexSupported = indexSupportedBasisfunctions(x); - - values.reserve(indexSupported.size()); - - // Evaluate nonzero basis functions - for (auto it = indexSupported.begin(); it != indexSupported.end(); ++it) - { - double val = deBoorCox(x, *it, degree); - if (std::abs(val) > 1e-12) - values.insert(*it) = val; - } - - // Alternative evaluation using basis matrix -// int knotIndex = indexHalfopenInterval(x); // knot index - -// SparseMatrix basisvalues2 = buildBsplineMatrix(x, knotIndex, 1); -// for (int i = 2; i <= basisDegree; i++) -// { -// SparseMatrix Ri = buildBsplineMatrix(x, knotIndex, i); -// basisvalues2 = basisvalues2*Ri; -// } -// basisvalues2.makeCompressed(); - -// assert(basisvalues2.rows() == 1); -// assert(basisvalues2.cols() == basisDegree + 1); - - return values; -} - -SparseVector BSplineBasis1D::evalDerivative(double x, int r) const -{ - // Evaluate rth derivative of basis functions at x - // Returns vector [D^(r)B_(u-p,p)(x) ... D^(r)B_(u,p)(x)] - // where u is the knot index and p is the degree - int p = degree; - - // Continuity requirement - //assert(p > r); - if (p <= r) - { - // Return zero-gradient - SparseVector DB(getNumBasisFunctions()); - return DB; - } - - // Check for knot multiplicity here! - - supportHack(x); - - int knotIndex = indexHalfopenInterval(x); - - // Algorithm 3.18 from Lyche and Moerken (2011) - SparseMatrix B(1,1); - B.insert(0,0) = 1; - - for (int i = 1; i <= p-r; i++) - { - SparseMatrix R = buildBasisMatrix(x, knotIndex, i); - B = B*R; - } - - for (int i = p-r+1; i <= p; i++) - { - SparseMatrix DR = buildBasisMatrix(x, knotIndex, i, true); - B = B*DR; - } - double factorial = std::tgamma(p+1)/std::tgamma(p-r+1); - B = B*factorial; - - if (B.cols() != p+1) - throw Exception("BSplineBasis1D::evalDerivative: Wrong number of columns of B matrix."); - - // From row vector to extended column vector - SparseVector DB(getNumBasisFunctions()); - DB.reserve(p+1); - int i = knotIndex-p; // First insertion index - for (int k = 0; k < B.outerSize(); ++k) - for (SparseMatrix::InnerIterator it(B,k); it; ++it) - { - DB.insert(i+it.col()) = it.value(); - } - - return DB; -} - -// Old implementation of first derivative of basis functions -SparseVector BSplineBasis1D::evalFirstDerivative(double x) const -{ - SparseVector values(getNumBasisFunctions()); - - supportHack(x); - - std::vector supportedBasisFunctions = indexSupportedBasisfunctions(x); - - for (int i : supportedBasisFunctions) - { - // Differentiate basis function - // Equation 3.35 in Lyche & Moerken (2011) - double b1 = deBoorCox(x, i, degree-1); - double b2 = deBoorCox(x, i+1, degree-1); - - double t11 = knots.at(i); - double t12 = knots.at(i+degree); - double t21 = knots.at(i+1); - double t22 = knots.at(i+degree+1); - - (t12 == t11) ? b1 = 0 : b1 = b1/(t12-t11); - (t22 == t21) ? b2 = 0 : b2 = b2/(t22-t21); - - values.insert(i) = degree*(b1 - b2); - } - - return values; -} - -// Used to evaluate basis functions - alternative to the recursive deBoorCox -SparseMatrix BSplineBasis1D::buildBasisMatrix(double x, unsigned int u, unsigned int k, bool diff) const -{ - /* Build B-spline Matrix - * R_k in R^(k,k+1) - * or, if diff = true, the differentiated basis matrix - * DR_k in R^(k,k+1) - */ - - if (!(k >= 1 && k <= getBasisDegree())) - { - throw Exception("BSplineBasis1D::buildBasisMatrix: Incorrect input paramaters!"); - } - -// assert(u >= basisDegree + 1); -// assert(u < ks.size() - basisDegree); - - unsigned int rows = k; - unsigned int cols = k+1; - SparseMatrix R(rows, cols); - R.reserve(Eigen::VectorXi::Constant(cols, 2)); - - for (unsigned int i = 0; i < rows; i++) - { - double dk = knots.at(u+1+i) - knots.at(u+1+i-k); - if (dk == 0) - { - continue; - } - else - { - if (diff) - { - // Insert diagonal element - R.insert(i,i) = -1/dk; - - // Insert super-diagonal element - R.insert(i,i+1) = 1/dk; - } - else - { - // Insert diagonal element - double a = (knots.at(u+1+i) - x)/dk; - if (a != 0) - R.insert(i,i) = a; - - // Insert super-diagonal element - double b = (x - knots.at(u+1+i-k))/dk; - if (b != 0) - R.insert(i,i+1) = b; - } - } - } - - R.makeCompressed(); - - return R; -} - -double BSplineBasis1D::deBoorCox(double x, int i, int k) const -{ - if (k == 0) - { - if (inHalfopenInterval(x, knots.at(i), knots.at(i+1))) - return 1; - else - return 0; - } - else - { - double s1,s2,r1,r2; - - s1 = deBoorCoxCoeff(x, knots.at(i), knots.at(i+k)); - s2 = deBoorCoxCoeff(x, knots.at(i+1), knots.at(i+k+1)); - - r1 = deBoorCox(x, i, k-1); - r2 = deBoorCox(x, i+1, k-1); - - return s1*r1 + (1-s2)*r2; - } -} - -double BSplineBasis1D::deBoorCoxCoeff(double x, double x_min, double x_max) const -{ - if (x_min < x_max && x_min <= x && x <= x_max) - return (x - x_min)/(x_max - x_min); - return 0; -} - -// Insert knots and compute knot insertion matrix (to update control points) -SparseMatrix BSplineBasis1D::insertKnots(double tau, unsigned int multiplicity) -{ - if (!insideSupport(tau)) - throw Exception("BSplineBasis1D::insertKnots: Cannot insert knot outside domain!"); - - if (knotMultiplicity(tau) + multiplicity > degree + 1) - throw Exception("BSplineBasis1D::insertKnots: Knot multiplicity is too high!"); - - // New knot vector - int index = indexHalfopenInterval(tau); - - std::vector extKnots = knots; - for (unsigned int i = 0; i < multiplicity; i++) - extKnots.insert(extKnots.begin()+index+1, tau); - - if (!isKnotVectorRegular(extKnots, degree)) - throw Exception("BSplineBasis1D::insertKnots: New knot vector is not regular!"); - - // Return knot insertion matrix - SparseMatrix A = buildKnotInsertionMatrix(extKnots); - - // Update knots - knots = extKnots; - - return A; -} - -SparseMatrix BSplineBasis1D::refineKnots() -{ - // Build refine knot vector - std::vector refinedKnots = knots; - - unsigned int targetNumKnots = targetNumBasisfunctions + degree + 1; - while (refinedKnots.size() < targetNumKnots) - { - int index = indexLongestInterval(refinedKnots); - double newKnot = (refinedKnots.at(index) + refinedKnots.at(index+1))/2.0; - refinedKnots.insert(std::lower_bound(refinedKnots.begin(), refinedKnots.end(), newKnot), newKnot); - } - - if (!isKnotVectorRegular(refinedKnots, degree)) - throw Exception("BSplineBasis1D::refineKnots: New knot vector is not regular!"); - - if (!isKnotVectorRefinement(knots, refinedKnots)) - throw Exception("BSplineBasis1D::refineKnots: New knot vector is not a proper refinement!"); - - // Return knot insertion matrix - SparseMatrix A = buildKnotInsertionMatrix(refinedKnots); - - // Update knots - knots = refinedKnots; - - return A; -} - -SparseMatrix BSplineBasis1D::refineKnotsLocally(double x) -{ - if (!insideSupport(x)) - throw Exception("BSplineBasis1D::refineKnotsLocally: Cannot refine outside support!"); - - if (getNumBasisFunctions() >= getNumBasisFunctionsTarget() - || assertNear(knots.front(), knots.back())) - { - unsigned int n = getNumBasisFunctions(); - DenseMatrix A = DenseMatrix::Identity(n,n); - return A.sparseView(); - } - - // Refined knot vector - std::vector refinedKnots = knots; - - auto upper = std::lower_bound(refinedKnots.begin(), refinedKnots.end(), x); - - // Check left boundary - if (upper == refinedKnots.begin()) - std::advance(upper, degree+1); - - // Get previous iterator - auto lower = std::prev(upper); - - // Do not insert if upper and lower bounding knot are close - if (assertNear(*upper, *lower)) - { - unsigned int n = getNumBasisFunctions(); - DenseMatrix A = DenseMatrix::Identity(n,n); - return A.sparseView(); - } - - // Insert knot at x - double insertVal = x; - - // Adjust x if it is on or close to a knot - if (knotMultiplicity(x) > 0 - || assertNear(*upper, x, 1e-6, 1e-6) - || assertNear(*lower, x, 1e-6, 1e-6)) - { - insertVal = (*upper + *lower)/2.0; - } - - // Insert new knot - refinedKnots.insert(upper, insertVal); - - if (!isKnotVectorRegular(refinedKnots, degree)) - throw Exception("BSplineBasis1D::refineKnotsLocally: New knot vector is not regular!"); - - if (!isKnotVectorRefinement(knots, refinedKnots)) - throw Exception("BSplineBasis1D::refineKnotsLocally: New knot vector is not a proper refinement!"); - - // Build knot insertion matrix - SparseMatrix A = buildKnotInsertionMatrix(refinedKnots); - - // Update knots - knots = refinedKnots; - - return A; -} - -SparseMatrix BSplineBasis1D::decomposeToBezierForm() -{ - // Build refine knot vector - std::vector refinedKnots = knots; - - // Start at first knot and add knots until all knots have multiplicity degree + 1 - std::vector::iterator knoti = refinedKnots.begin(); - while (knoti != refinedKnots.end()) - { - // Insert new knots - int mult = degree + 1 - knotMultiplicity(*knoti); - if (mult > 0) - { - std::vector newKnots(mult, *knoti); - refinedKnots.insert(knoti, newKnots.begin(), newKnots.end()); - } - - // Advance to next knot - knoti = std::upper_bound(refinedKnots.begin(), refinedKnots.end(), *knoti); - } - - if (!isKnotVectorRegular(refinedKnots, degree)) - throw Exception("BSplineBasis1D::refineKnots: New knot vector is not regular!"); - - if (!isKnotVectorRefinement(knots, refinedKnots)) - throw Exception("BSplineBasis1D::refineKnots: New knot vector is not a proper refinement!"); - - // Return knot insertion matrix - SparseMatrix A = buildKnotInsertionMatrix(refinedKnots); - - // Update knots - knots = refinedKnots; - - return A; -} - -SparseMatrix BSplineBasis1D::buildKnotInsertionMatrix(const std::vector &refinedKnots) const -{ - if (!isKnotVectorRegular(refinedKnots, degree)) - throw Exception("BSplineBasis1D::buildKnotInsertionMatrix: New knot vector is not regular!"); - - if (!isKnotVectorRefinement(knots, refinedKnots)) - throw Exception("BSplineBasis1D::buildKnotInsertionMatrix: New knot vector is not a proper refinement!"); - - std::vector knotsAug = refinedKnots; - unsigned int n = knots.size() - degree - 1; - unsigned int m = knotsAug.size() - degree - 1; - - SparseMatrix A(m, n); - //A.resize(m,n); - A.reserve(Eigen::VectorXi::Constant(n, degree + 1)); - - // Build A row-by-row - for (unsigned int i = 0; i < m; i++) - { - int u = indexHalfopenInterval(knotsAug.at(i)); - - SparseMatrix R(1,1); - R.insert(0,0) = 1; - - // For p > 0 - for (unsigned int j = 1; j <= degree; j++) - { - SparseMatrix Ri = buildBasisMatrix(knotsAug.at(i + j), u, j); - R = R*Ri; - } - - // Size check - if (R.rows() != 1 || R.cols() != (int)degree + 1) - { - throw Exception("BSplineBasis1D::buildKnotInsertionMatrix: Incorrect matrix dimensions!"); - } - - // Insert row values - int j = u - degree; // First insertion index - for (int k = 0; k < R.outerSize(); ++k) - for (SparseMatrix::InnerIterator it(R, k); it; ++it) - { - A.insert(i, j + it.col()) = it.value(); - } - } - - A.makeCompressed(); - - return A; -} - -/* - * The B-spline domain is the half-open domain [ knots.first(), knots.end() ). - * The hack checks if x is at the right boundary (if x = knots.end()), if so, - * a small number is subtracted from x, moving x into the half-open domain. - */ -void BSplineBasis1D::supportHack(double &x) const -{ - if (x == knots.back()) - x = std::nextafter(x, std::numeric_limits::lowest()); -} - -/* - * Finds index i such that knots.at(i) <= x < knots.at(i+1). - * Returns false if x is outside support. - */ -int BSplineBasis1D::indexHalfopenInterval(double x) const -{ - if (x < knots.front() || x > knots.back()) - throw Exception("BSplineBasis1D::indexHalfopenInterval: x outside knot interval!"); - - // Find first knot that is larger than x - std::vector::const_iterator it = std::upper_bound(knots.begin(), knots.end(), x); - - // Return index - int index = it - knots.begin(); - return index - 1; -} - -SparseMatrix BSplineBasis1D::reduceSupport(double lb, double ub) -{ - // Check bounds - if (lb < knots.front() || ub > knots.back()) - throw Exception("BSplineBasis1D::reduceSupport: Cannot increase support!"); - - unsigned int k = degree + 1; - - int index_lower = indexSupportedBasisfunctions(lb).front(); - int index_upper = indexSupportedBasisfunctions(ub).back(); - - // Check lower bound index - if (k != knotMultiplicity(knots.at(index_lower))) - { - int suggested_index = index_lower - 1; - if (0 <= suggested_index) - { - index_lower = suggested_index; - } - else - { - throw Exception("BSplineBasis1D::reduceSupport: Suggested index is negative!"); - } - } - - // Check upper bound index - if (knotMultiplicity(ub) == k && knots.at(index_upper) == ub) - { - index_upper -= k; - } - - // New knot vector - std::vector si; - si.insert(si.begin(), knots.begin()+index_lower, knots.begin()+index_upper+k+1); - - // Construct selection matrix A - int numOld = knots.size()-k; // Current number of basis functions - int numNew = si.size()-k; // Number of basis functions after update - - if (numOld < numNew) - throw Exception("BSplineBasis1D::reduceSupport: Number of basis functions is increased instead of reduced!"); - - DenseMatrix Ad = DenseMatrix::Zero(numOld, numNew); - Ad.block(index_lower, 0, numNew, numNew) = DenseMatrix::Identity(numNew, numNew); - SparseMatrix A = Ad.sparseView(); - - // Update knots - knots = si; - - return A; -} - -double BSplineBasis1D::getKnotValue(unsigned int index) const -{ - return knots.at(index); -} - -unsigned int BSplineBasis1D::knotMultiplicity(double tau) const -{ - return std::count(knots.begin(), knots.end(), tau); -} - -bool BSplineBasis1D::inHalfopenInterval(double x, double x_min, double x_max) const -{ - return (x_min <= x) && (x < x_max); -} - -bool BSplineBasis1D::insideSupport(double x) const -{ - return (knots.front() <= x) && (x <= knots.back()); -} - -unsigned int BSplineBasis1D::getNumBasisFunctions() const -{ - return knots.size() - (degree + 1); -} - -unsigned int BSplineBasis1D::getNumBasisFunctionsTarget() const -{ - return targetNumBasisfunctions; -} - -// Return indices of supporting basis functions at x -std::vector BSplineBasis1D::indexSupportedBasisfunctions(double x) const -{ - std::vector ret; - if (insideSupport(x)) - { - int last = indexHalfopenInterval(x); - if (last < 0) - { - // NOTE: can this happen? - last = knots.size() - 1 - (degree + 1); - } - int first = std::max((int)(last - degree), 0); - for (int i = first; i <= last; i++) - { - ret.push_back(i); - } - } - return ret; -} - -unsigned int BSplineBasis1D::indexLongestInterval() const -{ - return indexLongestInterval(knots); -} - -unsigned int BSplineBasis1D::indexLongestInterval(const std::vector &vec) const -{ - double longest = 0; - double interval = 0; - unsigned int index = 0; - - for (unsigned int i = 0; i < vec.size() - 1; i++) - { - interval = vec.at(i+1) - vec.at(i); - if (longest < interval) - { - longest = interval; - index = i; - } - } - return index; -} - -} // namespace SPLINTER diff --git a/splinter/bsplinebasis1d.h b/splinter/bsplinebasis1d.h deleted file mode 100644 index 203fb5299c..0000000000 --- a/splinter/bsplinebasis1d.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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 SPLINTER_BSPLINEBASIS1D_H -#define SPLINTER_BSPLINEBASIS1D_H - -#include "definitions.h" - -namespace SPLINTER -{ - -class BSplineBasis1D -{ -public: - BSplineBasis1D(); - BSplineBasis1D(const std::vector &knots, unsigned int degree); - - // Evaluation of basis functions - SparseVector eval(double x) const; - SparseVector evalDerivative(double x, int r) const; - SparseVector evalFirstDerivative(double x) const; // Depricated - - // Knot vector related - SparseMatrix refineKnots(); - SparseMatrix refineKnotsLocally(double x); - SparseMatrix decomposeToBezierForm(); - SparseMatrix insertKnots(double tau, unsigned int multiplicity = 1); - // bool insertKnots(SparseMatrix &A, std::vector> newKnots); // Add knots at several locations - unsigned int knotMultiplicity(double tau) const; // Returns the number of repetitions of tau in the knot vector - - // Support related - void supportHack(double &x) const; - bool insideSupport(double x) const; - SparseMatrix reduceSupport(double lb, double ub); - - // Getters - std::vector getKnotVector() const { return knots; } - unsigned int getBasisDegree() const { return degree; } - double getKnotValue(unsigned int index) const; - unsigned int getNumBasisFunctions() const; - unsigned int getNumBasisFunctionsTarget() const; - - // Index getters - std::vector indexSupportedBasisfunctions(double x) const; - int indexHalfopenInterval(double x) const; - unsigned int indexLongestInterval() const; - unsigned int indexLongestInterval(const std::vector &vec) const; - - // Setters - void setNumBasisFunctionsTarget(unsigned int target) - { - targetNumBasisfunctions = std::max(degree+1, target); - } - -private: - // DeBoorCox algorithm for evaluating basis functions - double deBoorCox(double x, int i, int k) const; - double deBoorCoxCoeff(double x, double x_min, double x_max) const; - - // Builds basis matrix for alternative evaluation of basis functions - SparseMatrix buildBasisMatrix(double x, unsigned int u, unsigned int k, bool diff = false) const; - - /* - * Builds knot insertion matrix - * Implements Oslo Algorithm 1 from Lyche and Moerken (2011). Spline methods draft. - */ - SparseMatrix buildKnotInsertionMatrix(const std::vector &refinedKnots) const; - - // Helper functions - bool inHalfopenInterval(double x, double x_min, double x_max) const; - - // Member variables - unsigned int degree; - std::vector knots; - unsigned int targetNumBasisfunctions; - - friend class Serializer; - friend bool operator==(const BSplineBasis1D &lhs, const BSplineBasis1D &rhs); - friend bool operator!=(const BSplineBasis1D &lhs, const BSplineBasis1D &rhs); -}; - -} // namespace SPLINTER - -#endif // SPLINTER_BSPLINEBASIS1D_H diff --git a/splinter/bsplinebuilder.cpp b/splinter/bsplinebuilder.cpp deleted file mode 100644 index 9d0c57a4e0..0000000000 --- a/splinter/bsplinebuilder.cpp +++ /dev/null @@ -1,558 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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/. -*/ - -#include -#include "bsplinebuilder.h" -#include "mykroneckerproduct.h" -#include "unsupported/Eigen/KroneckerProduct" -#include "linearsolvers.h" -#include "serializer.h" -#include "utilities.h" - -namespace SPLINTER -{ -// Default constructor -BSpline::Builder::Builder(const DataTable &data) - : - _data(data), - _degrees(getBSplineDegrees(data.getNumVariables(), 3)), - _numBasisFunctions(std::vector(data.getNumVariables(), 0)), - _knotSpacing(KnotSpacing::AS_SAMPLED), - _smoothing(Smoothing::NONE), - _alpha(0.1) -{ -} - -/* - * Build B-spline - */ -BSpline BSpline::Builder::build() const -{ - // Check data - // TODO: Remove this test - if (!_data.isGridComplete()) - throw Exception("BSpline::Builder::build: Cannot create B-spline from irregular (incomplete) grid."); - - // Build knot vectors - auto knotVectors = computeKnotVectors(); - - // Build B-spline (with default coefficients) - auto bspline = BSpline(knotVectors, _degrees); - - // Compute coefficients from samples and update B-spline - auto coefficients = computeCoefficients(bspline); - bspline.setCoefficients(coefficients); - - return bspline; -} - -/* - * Find coefficients of B-spline by solving: - * min ||A*x - b||^2 + alpha*||R||^2, - * where - * A = mxn matrix of n basis functions evaluated at m sample points, - * b = vector of m sample points y-values (or x-values when calculating knot averages), - * x = B-spline coefficients (or knot averages), - * R = Regularization matrix, - * alpha = regularization parameter. - */ -DenseVector BSpline::Builder::computeCoefficients(const BSpline& bspline) const -{ - SparseMatrix B = computeBasisFunctionMatrix(bspline); - SparseMatrix A = B; - DenseVector b = getSamplePointValues(); - - if (_smoothing == Smoothing::IDENTITY) - { - /* - * Computing B-spline coefficients with a regularization term - * ||Ax-b||^2 + alpha*x^T*x - * - * NOTE: This corresponds to a Tikhonov regularization (or ridge regression) with the Identity matrix. - * See: https://en.wikipedia.org/wiki/Tikhonov_regularization - * - * NOTE2: consider changing regularization factor to (alpha/numSample) - */ - SparseMatrix Bt = B.transpose(); - A = Bt*B; - b = Bt*b; - - auto I = SparseMatrix(A.cols(), A.cols()); - I.setIdentity(); - A += _alpha*I; - } - else if (_smoothing == Smoothing::PSPLINE) - { - /* - * The P-Spline is a smooting B-spline which relaxes the interpolation constraints on the control points to allow - * smoother spline curves. It minimizes an objective which penalizes both deviation from sample points (to lower bias) - * and the magnitude of second derivatives (to lower variance). - * - * Setup and solve equations Ax = b, - * A = B'*W*B + l*D'*D - * b = B'*W*y - * x = control coefficients or knot averages. - * B = basis functions at sample x-values, - * W = weighting matrix for interpolating specific points - * D = second-order finite difference matrix - * l = penalizing parameter (increase for more smoothing) - * y = sample y-values when calculating control coefficients, - * y = sample x-values when calculating knot averages - */ - - // Assuming regular grid - unsigned int numSamples = _data.getNumSamples(); - - SparseMatrix Bt = B.transpose(); - - // Weight matrix - SparseMatrix W; - W.resize(numSamples, numSamples); - W.setIdentity(); - - // Second order finite difference matrix - SparseMatrix D = getSecondOrderFiniteDifferenceMatrix(bspline); - - // Left-hand side matrix - A = Bt*W*B + _alpha*D.transpose()*D; - - // Compute right-hand side matrices - b = Bt*W*b; - } - - DenseVector x; - - int numEquations = A.rows(); - int maxNumEquations = 100; - bool solveAsDense = (numEquations < maxNumEquations); - - if (!solveAsDense) - { -#ifndef NDEBUG - std::cout << "BSpline::Builder::computeBSplineCoefficients: Computing B-spline control points using sparse solver." << std::endl; -#endif // NDEBUG - - SparseLU<> s; - //bool successfulSolve = (s.solve(A,Bx,Cx) && s.solve(A,By,Cy)); - - solveAsDense = !s.solve(A, b, x); - } - - if (solveAsDense) - { -#ifndef NDEBUG - std::cout << "BSpline::Builder::computeBSplineCoefficients: Computing B-spline control points using dense solver." << std::endl; -#endif // NDEBUG - - DenseMatrix Ad = A.toDense(); - DenseQR s; - // DenseSVD s; - //bool successfulSolve = (s.solve(Ad,Bx,Cx) && s.solve(Ad,By,Cy)); - if (!s.solve(Ad, b, x)) - { - throw Exception("BSpline::Builder::computeBSplineCoefficients: Failed to solve for B-spline coefficients."); - } - } - - return x; -} - -SparseMatrix BSpline::Builder::computeBasisFunctionMatrix(const BSpline &bspline) const -{ - unsigned int numVariables = _data.getNumVariables(); - unsigned int numSamples = _data.getNumSamples(); - - // TODO: Reserve nnz per row (degree+1) - //int nnzPrCol = bspline.basis.supportedPrInterval(); - - SparseMatrix A(numSamples, bspline.getNumBasisFunctions()); - //A.reserve(DenseVector::Constant(numSamples, nnzPrCol)); // TODO: should reserve nnz per row! - - int i = 0; - for (auto it = _data.cbegin(); it != _data.cend(); ++it, ++i) - { - DenseVector xi(numVariables); - xi.setZero(); - std::vector xv = it->getX(); - for (unsigned int j = 0; j < numVariables; ++j) - { - xi(j) = xv.at(j); - } - - SparseVector basisValues = bspline.evalBasis(xi); - - for (SparseVector::InnerIterator it2(basisValues); it2; ++it2) - { - A.insert(i,it2.index()) = it2.value(); - } - } - - A.makeCompressed(); - - return A; -} - -DenseVector BSpline::Builder::getSamplePointValues() const -{ - DenseVector B = DenseVector::Zero(_data.getNumSamples()); - - int i = 0; - for (auto it = _data.cbegin(); it != _data.cend(); ++it, ++i) - B(i) = it->getY(); - - return B; -} - -/* -* Function for generating second order finite-difference matrix, which is used for penalizing the -* (approximate) second derivative in control point calculation for P-splines. -*/ -SparseMatrix BSpline::Builder::getSecondOrderFiniteDifferenceMatrix(const BSpline &bspline) const -{ - unsigned int numVariables = bspline.getNumVariables(); - - // Number of (total) basis functions - defines the number of columns in D - unsigned int numCols = bspline.getNumBasisFunctions(); - std::vector numBasisFunctions = bspline.getNumBasisFunctionsPerVariable(); - - // Number of basis functions (and coefficients) in each variable - std::vector dims; - for (unsigned int i = 0; i < numVariables; i++) - dims.push_back(numBasisFunctions.at(i)); - - std::reverse(dims.begin(), dims.end()); - - for (unsigned int i=0; i < numVariables; ++i) - if (numBasisFunctions.at(i) < 3) - throw Exception("BSpline::Builder::getSecondOrderDifferenceMatrix: Need at least three coefficients/basis function per variable."); - - // Number of rows in D and in each block - int numRows = 0; - std::vector< int > numBlkRows; - for (unsigned int i = 0; i < numVariables; i++) - { - int prod = 1; - for (unsigned int j = 0; j < numVariables; j++) - { - if (i == j) - prod *= (dims[j] - 2); - else - prod *= dims[j]; - } - numRows += prod; - numBlkRows.push_back(prod); - } - - // Resize and initialize D - SparseMatrix D(numRows, numCols); - D.reserve(DenseVector::Constant(numCols,2*numVariables)); // D has no more than two elems per col per dim - - int i = 0; // Row index - // Loop though each dimension (each dimension has its own block) - for (unsigned int d = 0; d < numVariables; d++) - { - // Calculate left and right products - int leftProd = 1; - int rightProd = 1; - for (unsigned int k = 0; k < d; k++) - { - leftProd *= dims[k]; - } - for (unsigned int k = d+1; k < numVariables; k++) - { - rightProd *= dims[k]; - } - - // Loop through subblocks on the block diagonal - for (int j = 0; j < rightProd; j++) - { - // Start column of current subblock - int blkBaseCol = j*leftProd*dims[d]; - // Block rows [I -2I I] of subblock - for (unsigned int l = 0; l < (dims[d] - 2); l++) - { - // Special case for first dimension - if (d == 0) - { - int k = j*leftProd*dims[d] + l; - D.insert(i,k) = 1; - k += leftProd; - D.insert(i,k) = -2; - k += leftProd; - D.insert(i,k) = 1; - i++; - } - else - { - // Loop for identity matrix - for (int n = 0; n < leftProd; n++) - { - int k = blkBaseCol + l*leftProd + n; - D.insert(i,k) = 1; - k += leftProd; - D.insert(i,k) = -2; - k += leftProd; - D.insert(i,k) = 1; - i++; - } - } - } - } - } - - D.makeCompressed(); - - return D; -} - -// Compute all knot vectors from sample data -std::vector > BSpline::Builder::computeKnotVectors() const -{ - if (_data.getNumVariables() != _degrees.size()) - throw Exception("BSpline::Builder::computeKnotVectors: Inconsistent sizes on input vectors."); - - std::vector> grid = _data.getTableX(); - - std::vector> knotVectors; - - for (unsigned int i = 0; i < _data.getNumVariables(); ++i) - { - // Compute knot vector - auto knotVec = computeKnotVector(grid.at(i), _degrees.at(i), _numBasisFunctions.at(i)); - - knotVectors.push_back(knotVec); - } - - return knotVectors; -} - -// Compute a single knot vector from sample grid and degree -std::vector BSpline::Builder::computeKnotVector(const std::vector &values, - unsigned int degree, - unsigned int numBasisFunctions) const -{ - switch (_knotSpacing) - { - case KnotSpacing::AS_SAMPLED: - return knotVectorMovingAverage(values, degree); - case KnotSpacing::EQUIDISTANT: - return knotVectorEquidistant(values, degree, numBasisFunctions); - case KnotSpacing::EXPERIMENTAL: - return knotVectorBuckets(values, degree); - default: - return knotVectorMovingAverage(values, degree); - } -} - -/* -* Automatic construction of (p+1)-regular knot vector -* using moving average. -* -* Requirement: -* Knot vector should be of size n+p+1. -* End knots are should be repeated p+1 times. -* -* Computed sizes: -* n+2*(p) = n + p + 1 + (p - 1) -* k = (p - 1) values must be removed from sample vector. -* w = k + 3 window size in moving average -* -* Algorithm: -* 1) compute n - k values using moving average with window size w -* 2) repeat first and last value p + 1 times -* -* The resulting knot vector has n - k + 2*p = n + p + 1 knots. -* -* NOTE: -* For equidistant samples, the resulting knot vector is identically to -* the free end conditions knot vector used in cubic interpolation. -* That is, samples (a,b,c,d,e,f) produces the knot vector (a,a,a,a,c,d,f,f,f,f) for p = 3. -* For p = 1, (a,b,c,d,e,f) becomes (a,a,b,c,d,e,f,f). -* -* TODO: -* Does not work well when number of knots is << number of samples! For such cases -* almost all knots will lie close to the left samples. Try a bucket approach, where the -* samples are added to buckets and the knots computed as the average of these. -*/ -std::vector BSpline::Builder::knotVectorMovingAverage(const std::vector &values, - unsigned int degree) const -{ - // Sort and remove duplicates - std::vector unique = extractUniqueSorted(values); - - // Compute sizes - unsigned int n = unique.size(); - unsigned int k = degree-1; // knots to remove - unsigned int w = k + 3; // Window size - - // The minimum number of samples from which a free knot vector can be created - if (n < degree+1) - { - std::ostringstream e; - e << "knotVectorMovingAverage: Only " << n - << " unique interpolation points are given. A minimum of degree+1 = " << degree+1 - << " unique points are required to build a B-spline basis of degree " << degree << "."; - throw Exception(e.str()); - } - - std::vector knots(n-k-2, 0); - - // Compute (n-k-2) interior knots using moving average - for (unsigned int i = 0; i < n-k-2; ++i) - { - double ma = 0; - for (unsigned int j = 0; j < w; ++j) - ma += unique.at(i+j); - - knots.at(i) = ma/w; - } - - // Repeat first knot p + 1 times (for interpolation of start point) - for (unsigned int i = 0; i < degree + 1; ++i) - knots.insert(knots.begin(), unique.front()); - - // Repeat last knot p + 1 times (for interpolation of end point) - for (unsigned int i = 0; i < degree + 1; ++i) - knots.insert(knots.end(), unique.back()); - - // Number of knots in a (p+1)-regular knot vector - //assert(knots.size() == uniqueX.size() + degree + 1); - - return knots; -} - -std::vector BSpline::Builder::knotVectorEquidistant(const std::vector &values, - unsigned int degree, - unsigned int numBasisFunctions = 0) const -{ - // Sort and remove duplicates - std::vector unique = extractUniqueSorted(values); - - // Compute sizes - unsigned int n = unique.size(); - if (numBasisFunctions > 0) - n = numBasisFunctions; - unsigned int k = degree-1; // knots to remove - - // The minimum number of samples from which a free knot vector can be created - if (n < degree+1) - { - std::ostringstream e; - e << "knotVectorMovingAverage: Only " << n - << " unique interpolation points are given. A minimum of degree+1 = " << degree+1 - << " unique points are required to build a B-spline basis of degree " << degree << "."; - throw Exception(e.str()); - } - - // Compute (n-k-2) equidistant interior knots - unsigned int numIntKnots = std::max(n-k-2, (unsigned int)0); - numIntKnots = std::min((unsigned int)10, numIntKnots); - std::vector knots = linspace(unique.front(), unique.back(), numIntKnots); - - // Repeat first knot p + 1 times (for interpolation of start point) - for (unsigned int i = 0; i < degree; ++i) - knots.insert(knots.begin(), unique.front()); - - // Repeat last knot p + 1 times (for interpolation of end point) - for (unsigned int i = 0; i < degree; ++i) - knots.insert(knots.end(), unique.back()); - - // Number of knots in a (p+1)-regular knot vector - //assert(knots.size() == uniqueX.size() + degree + 1); - - return knots; -} - -std::vector BSpline::Builder::knotVectorBuckets(const std::vector &values, unsigned int degree, unsigned int maxSegments) const -{ - // Sort and remove duplicates - std::vector unique = extractUniqueSorted(values); - - // The minimum number of samples from which a free knot vector can be created - if (unique.size() < degree+1) - { - std::ostringstream e; - e << "BSpline::Builder::knotVectorBuckets: Only " << unique.size() - << " unique sample points are given. A minimum of degree+1 = " << degree+1 - << " unique points are required to build a B-spline basis of degree " << degree << "."; - throw Exception(e.str()); - } - - // Num internal knots (0 <= ni <= unique.size() - degree - 1) - unsigned int ni = unique.size() - degree - 1; - - // Num segments - unsigned int ns = ni + degree + 1; - - // Limit number of segments - if (ns > maxSegments && maxSegments >= degree + 1) - { - ns = maxSegments; - ni = ns - degree - 1; - } - - // Num knots -// unsigned int nk = ns + degree + 1; - - // Check numbers - if (ni > unique.size() - degree - 1) - throw Exception("BSpline::Builder::knotVectorBuckets: Invalid number of internal knots!"); - - // Compute window sizes - unsigned int w = 0; - if (ni > 0) - w = (unsigned int)std::floor(unique.size()/ni); - - // Residual - unsigned int res = unique.size() - w*ni; - - // Create array with window sizes - std::vector windows(ni, w); - - // Add residual - for (unsigned int i = 0; i < res; ++i) - windows.at(i) += 1; - - // Compute internal knots - std::vector knots(ni, 0); - - // Compute (n-k-2) interior knots using moving average - unsigned int index = 0; - for (unsigned int i = 0; i < ni; ++i) - { - for (unsigned int j = 0; j < windows.at(i); ++j) - { - knots.at(i) += unique.at(index+j); - } - knots.at(i) /= windows.at(i); - index += windows.at(i); - } - - // Repeat first knot p + 1 times (for interpolation of start point) - for (unsigned int i = 0; i < degree + 1; ++i) - knots.insert(knots.begin(), unique.front()); - - // Repeat last knot p + 1 times (for interpolation of end point) - for (unsigned int i = 0; i < degree + 1; ++i) - knots.insert(knots.end(), unique.back()); - - return knots; -} - -std::vector BSpline::Builder::extractUniqueSorted(const std::vector &values) const -{ - // Sort and remove duplicates - std::vector unique(values); - std::sort(unique.begin(), unique.end()); - std::vector::iterator it = unique_copy(unique.begin(), unique.end(), unique.begin()); - unique.resize(distance(unique.begin(),it)); - return unique; -} - -} // namespace SPLINTER \ No newline at end of file diff --git a/splinter/bsplinebuilder.h b/splinter/bsplinebuilder.h deleted file mode 100644 index 7e56d325aa..0000000000 --- a/splinter/bsplinebuilder.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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 SPLINTER_BSPLINEBUILDER_H -#define SPLINTER_BSPLINEBUILDER_H - -#include "datatable.h" -#include "bspline.h" - -namespace SPLINTER -{ - -// B-spline smoothing -enum class BSpline::Smoothing -{ - NONE, // No smoothing - IDENTITY, // Regularization term alpha*c'*I*c is added to OLS objective - PSPLINE // Smoothing term alpha*Delta(c,2) is added to OLS objective -}; - -// B-spline knot spacing -/* - * To be added: - * AS_SAMPLED_NOT_CLAMPED // Place knots close to sample points. Without clamps. - * EQUIDISTANT_NOT_CLAMPED // Equidistant knots without clamps. - */ -enum class BSpline::KnotSpacing -{ - AS_SAMPLED, // Mimic spacing of sample points (moving average). With clamps (p+1 multiplicity of end knots). - EQUIDISTANT, // Equidistant knots. With clamps (p+1 multiplicity of end knots). - EXPERIMENTAL // Experimental knot spacing (for testing purposes). -}; - -// B-spline builder class -class SPLINTER_API BSpline::Builder -{ -public: - Builder(const DataTable &data); - - Builder& alpha(double alpha) - { - if (alpha < 0) - throw Exception("BSpline::Builder::alpha: alpha must be non-negative."); - - _alpha = alpha; - return *this; - } - - // Set build options - - Builder& degree(unsigned int degree) - { - _degrees = getBSplineDegrees(_data.getNumVariables(), degree); - return *this; - } - - Builder& degree(std::vector degrees) - { - if (degrees.size() != _data.getNumVariables()) - throw Exception("BSpline::Builder: Inconsistent length on degree vector."); - _degrees = degrees; - return *this; - } - - Builder& numBasisFunctions(unsigned int numBasisFunctions) - { - _numBasisFunctions = std::vector(_data.getNumVariables(), numBasisFunctions); - return *this; - } - - Builder& numBasisFunctions(std::vector numBasisFunctions) - { - if (numBasisFunctions.size() != _data.getNumVariables()) - throw Exception("BSpline::Builder: Inconsistent length on numBasisFunctions vector."); - _numBasisFunctions = numBasisFunctions; - return *this; - } - - Builder& knotSpacing(KnotSpacing knotSpacing) - { - _knotSpacing = knotSpacing; - return *this; - } - - Builder& smoothing(Smoothing smoothing) - { - _smoothing = smoothing; - return *this; - } - - // Build B-spline - BSpline build() const; - -private: - Builder(); - - std::vector getBSplineDegrees(unsigned int numVars, unsigned int degree) - { - if (degree > 5) - throw Exception("BSpline::Builder: Only degrees in range [0, 5] are supported."); - return std::vector(numVars, degree); - } - - // Control point computations - DenseVector computeCoefficients(const BSpline &bspline) const; - DenseVector computeBSplineCoefficients(const BSpline &bspline) const; - SparseMatrix computeBasisFunctionMatrix(const BSpline &bspline) const; - DenseVector getSamplePointValues() const; - // P-spline control point calculation - SparseMatrix getSecondOrderFiniteDifferenceMatrix(const BSpline &bspline) const; - - // Computing knots - std::vector> computeKnotVectors() const; - std::vector computeKnotVector(const std::vector &values, unsigned int degree, unsigned int numBasisFunctions) const; - std::vector knotVectorMovingAverage(const std::vector &values, unsigned int degree) const; - std::vector knotVectorEquidistant(const std::vector &values, unsigned int degree, unsigned int numBasisFunctions) const; - std::vector knotVectorBuckets(const std::vector &values, unsigned int degree, unsigned int maxSegments = 10) const; - - // Auxiliary - std::vector extractUniqueSorted(const std::vector &values) const; - - // Member variables - DataTable _data; - std::vector _degrees; - std::vector _numBasisFunctions; - KnotSpacing _knotSpacing; - Smoothing _smoothing; - double _alpha; -}; - -} // namespace SPLINTER - -#endif // SPLINTER_BSPLINEBUILDER_H diff --git a/splinter/datapoint.cpp b/splinter/datapoint.cpp deleted file mode 100644 index 8e2d5256ab..0000000000 --- a/splinter/datapoint.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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/. -*/ - -#include "datapoint.h" - -namespace SPLINTER -{ - -DataPoint::DataPoint() -{ -} - -DataPoint::DataPoint(double x, double y) -{ - setData(std::vector(1, x), y); -} - -DataPoint::DataPoint(std::vector x, double y) -{ - setData(x, y); -} - -DataPoint::DataPoint(DenseVector x, double y) -{ - std::vector newX; - - for (int i = 0; i < x.size(); i++) - { - newX.push_back(x(i)); - } - - setData(newX, y); -} - -void DataPoint::setData(const std::vector &x, double y) -{ - this->x = x; - this->y = y; -} - -bool DataPoint::operator<(const DataPoint &rhs) const -{ - if (this->getDimX() != rhs.getDimX()) - throw Exception("DataPoint::operator<: Cannot compare data points of different dimensions"); - - for (unsigned int i = 0; i < this->getDimX(); i++) - { - if (x.at(i) < rhs.getX().at(i)) - return true; - else if (x.at(i) > rhs.getX().at(i)) - return false; - } - - return false; -} - -/* -* Computes Euclidean distance ||x-y|| -*/ -double dist(const std::vector x, const std::vector y) -{ - if (x.size() != y.size()) - throw Exception("DataPoint::dist: Cannot measure distance between two points of different dimension"); - double sum = 0.0; - for (unsigned int i=0; i zeros(x.getDimX(), 0); - DataPoint origin(zeros, 0.0); - double x_dist = dist(x, origin); - double y_dist = dist(y, origin); - return (x_dist x, double y); - DataPoint(DenseVector x, double y); - - bool operator<(const DataPoint &rhs) const; // Returns false if the two are equal - - std::vector getX() const { return x; } - double getY() const { return y; } - unsigned int getDimX() const { return (unsigned int)x.size(); } - -private: - DataPoint(); - - std::vector x; - double y; - void setData(const std::vector &x, double y); - - friend class Serializer; -}; - -// Measure distance between two points -double dist(const std::vector x, const std::vector y); -double dist(const DataPoint x, const DataPoint y); -bool dist_sort(const DataPoint x, const DataPoint y); - -} // namespace SPLINTER - -#endif // SPLINTER_DATAPOINT_H diff --git a/splinter/datatable.cpp b/splinter/datatable.cpp deleted file mode 100644 index 24faafca02..0000000000 --- a/splinter/datatable.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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/. -*/ - -#include -#include -#include -#include -#include -#include -#include "datatable.h" -#include "serializer.h" - -namespace SPLINTER -{ - -DataTable::DataTable() - : DataTable(false, false) -{ -} - -DataTable::DataTable(bool allowDuplicates) - : DataTable(allowDuplicates, false) -{ -} - -DataTable::DataTable(bool allowDuplicates, bool allowIncompleteGrid) - : allowDuplicates(allowDuplicates), - allowIncompleteGrid(allowIncompleteGrid), - numDuplicates(0), - numVariables(0) -{ -} - -DataTable::DataTable(const char *fileName) - : DataTable(std::string(fileName)) -{ -} - -DataTable::DataTable(const std::string &fileName) -{ - load(fileName); -} - -void DataTable::addSample(double x, double y) -{ - addSample(DataPoint(x, y)); -} - -void DataTable::addSample(std::vector x, double y) -{ - addSample(DataPoint(x, y)); -} - -void DataTable::addSample(DenseVector x, double y) -{ - addSample(DataPoint(x, y)); -} - -void DataTable::addSample(const DataPoint &sample) -{ - if (getNumSamples() == 0) - { - numVariables = sample.getDimX(); - initDataStructures(); - } - - if(sample.getDimX() != numVariables) { - throw Exception("Datatable::addSample: Dimension of new sample is inconsistent with previous samples!"); - } - - // Check if the sample has been added already - if (samples.count(sample) > 0) - { - if (!allowDuplicates) - { -#ifndef NDEBUG - std::cout << "Discarding duplicate sample because allowDuplicates is false!" << std::endl; - std::cout << "Initialise with DataTable(true) to set it to true." << std::endl; -#endif // NDEBUG - - return; - } - - numDuplicates++; - } - - samples.insert(sample); - - recordGridPoint(sample); -} - -void DataTable::addSample(std::initializer_list samples) -{ - for (auto& sample : samples) - { - addSample(sample); - } -} - -void DataTable::recordGridPoint(const DataPoint &sample) -{ - for (unsigned int i = 0; i < getNumVariables(); i++) - { - grid.at(i).insert(sample.getX().at(i)); - } -} - -unsigned int DataTable::getNumSamplesRequired() const -{ - unsigned long samplesRequired = 1; - unsigned int i = 0; - for (auto &variable : grid) - { - samplesRequired *= (unsigned long) variable.size(); - i++; - } - - return (i > 0 ? samplesRequired : (unsigned long) 0); -} - -bool DataTable::isGridComplete() const -{ - return samples.size() > 0 && samples.size() - numDuplicates == getNumSamplesRequired(); -} - -void DataTable::initDataStructures() -{ - for (unsigned int i = 0; i < getNumVariables(); i++) - { - grid.push_back(std::set()); - } -} - -void DataTable::gridCompleteGuard() const -{ - if (!(isGridComplete() || allowIncompleteGrid)) - { - throw Exception("DataTable::gridCompleteGuard: The grid is not complete yet!"); - } -} - -void DataTable::save(const std::string &fileName) const -{ - Serializer s; - s.serialize(*this); - s.saveToFile(fileName); -} - -void DataTable::load(const std::string &fileName) -{ - Serializer s(fileName); - s.deserialize(*this); -} - -/* - * Getters for iterators - */ -std::multiset::const_iterator DataTable::cbegin() const -{ - return samples.cbegin(); -} - -std::multiset::const_iterator DataTable::cend() const -{ - return samples.cend(); -} - -/* - * Get table of samples x-values, - * i.e. table[i][j] is the value of variable i at sample j - */ -std::vector< std::vector > DataTable::getTableX() const -{ - gridCompleteGuard(); - - // Initialize table - std::vector> table; - for (unsigned int i = 0; i < numVariables; i++) - { - std::vector xi(getNumSamples(), 0.0); - table.push_back(xi); - } - - // Fill table with values - int i = 0; - for (auto &sample : samples) - { - std::vector x = sample.getX(); - - for (unsigned int j = 0; j < numVariables; j++) - { - table.at(j).at(i) = x.at(j); - } - i++; - } - - return table; -} - -// Get vector of y-values -std::vector DataTable::getVectorY() const -{ - std::vector y; - for (std::multiset::const_iterator it = cbegin(); it != cend(); ++it) - { - y.push_back(it->getY()); - } - return y; -} - -DataTable operator+(const DataTable &lhs, const DataTable &rhs) -{ - if(lhs.getNumVariables() != rhs.getNumVariables()) { - throw Exception("operator+(DataTable, DataTable): trying to add two DataTable's of different dimensions!"); - } - - DataTable result; - for(auto it = lhs.cbegin(); it != lhs.cend(); it++) { - result.addSample(*it); - } - for(auto it = rhs.cbegin(); it != rhs.cend(); it++) { - result.addSample(*it); - } - - return result; -} - -DataTable operator-(const DataTable &lhs, const DataTable &rhs) -{ - if(lhs.getNumVariables() != rhs.getNumVariables()) { - throw Exception("operator-(DataTable, DataTable): trying to subtract two DataTable's of different dimensions!"); - } - - DataTable result; - auto rhsSamples = rhs.getSamples(); - // Add all samples from lhs that are not in rhs - for(auto it = lhs.cbegin(); it != lhs.cend(); it++) { - if(rhsSamples.count(*it) == 0) { - result.addSample(*it); - } - } - - return result; -} - -} // namespace SPLINTER diff --git a/splinter/datatable.h b/splinter/datatable.h deleted file mode 100644 index d8255327c5..0000000000 --- a/splinter/datatable.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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 SPLINTER_DATATABLE_H -#define SPLINTER_DATATABLE_H - -#include -#include "datapoint.h" - -#include - -namespace SPLINTER -{ - -/* - * DataTable is a class for storing multidimensional data samples (x,y). - * The samples are stored in a continuously sorted table. - */ -class SPLINTER_API DataTable -{ -public: - DataTable(); - DataTable(bool allowDuplicates); - DataTable(bool allowDuplicates, bool allowIncompleteGrid); - DataTable(const char *fileName); - DataTable(const std::string &fileName); // Load DataTable from file - - /* - * Functions for adding a sample (x,y) - */ - void addSample(const DataPoint &sample); - void addSample(double x, double y); - void addSample(std::vector x, double y); - void addSample(DenseVector x, double y); - void addSample(std::initializer_list samples); - - /* - * Getters - */ - std::multiset::const_iterator cbegin() const; - std::multiset::const_iterator cend() const; - - unsigned int getNumVariables() const {return numVariables;} - unsigned int getNumSamples() const {return (unsigned int)samples.size();} - const std::multiset& getSamples() const {return samples;} - - std::vector> getGrid() const { return grid; } - std::vector< std::vector > getTableX() const; - std::vector getVectorY() const; - - bool isGridComplete() const; - - void save(const std::string &fileName) const; - - void clear() { samples.clear(); grid.clear(); } - -private: - bool allowDuplicates; - bool allowIncompleteGrid; - unsigned int numDuplicates; - unsigned int numVariables; - - std::multiset samples; - std::vector< std::set > grid; - - void initDataStructures(); // Initialise grid to be a std::vector of xDim std::sets - unsigned int getNumSamplesRequired() const; - - void recordGridPoint(const DataPoint &sample); - - // Used by functions that require the grid to be complete before they start their operation - // This function prints a message and exits the program if the grid is not complete. - void gridCompleteGuard() const; - - void load(const std::string &fileName); - - friend class Serializer; - friend bool operator==(const DataTable &lhs, const DataTable &rhs); -}; - -DataTable operator+(const DataTable &lhs, const DataTable &rhs); -DataTable operator-(const DataTable &lhs, const DataTable &rhs); - -} // namespace SPLINTER - -#endif // SPLINTER_DATATABLE_H diff --git a/splinter/function.cpp b/splinter/function.cpp deleted file mode 100644 index 6db20a0fcd..0000000000 --- a/splinter/function.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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/. -*/ - -#include "function.h" -#include "utilities.h" - -namespace SPLINTER -{ - -double Function::eval(const std::vector &x) const -{ - auto denseX = vectorToDenseVector(x); - - return eval(denseX); -} - -std::vector Function::evalJacobian(const std::vector &x) const -{ - auto denseX = vectorToDenseVector(x); - - return denseVectorToVector(evalJacobian(denseX)); -} - -std::vector> Function::evalHessian(const std::vector &x) const -{ - auto denseX = vectorToDenseVector(x); - - return denseMatrixToVectorVector(secondOrderCentralDifference(denseX)); -} - -std::vector Function::centralDifference(const std::vector &x) const -{ - auto denseX = vectorToDenseVector(x); - - auto dx = centralDifference(denseX); - - return denseVectorToVector(dx); -} - -std::vector> Function::secondOrderCentralDifference(const std::vector &x) const -{ - auto denseX = vectorToDenseVector(x); - - DenseMatrix ddx = secondOrderCentralDifference(denseX); - - return denseMatrixToVectorVector(ddx); -} - -DenseMatrix Function::evalJacobian(DenseVector x) const -{ - return centralDifference(x); -} - -DenseMatrix Function::evalHessian(DenseVector x) const -{ - auto vec = denseVectorToVector(x); - - auto hessian = evalHessian(vec); - - return vectorVectorToDenseMatrix(hessian); -} - -DenseMatrix Function::centralDifference(DenseVector x) const -{ - DenseMatrix dx(1, x.size()); - - double h = 1e-6; // perturbation step size - double hForward = 0.5*h; - double hBackward = 0.5*h; - - for (unsigned int i = 0; i < getNumVariables(); ++i) - { - DenseVector xForward(x); - xForward(i) = xForward(i) + hForward; - - DenseVector xBackward(x); - xBackward(i) = xBackward(i) - hBackward; - - double yForward = eval(xForward); - double yBackward = eval(xBackward); - - dx(i) = (yForward - yBackward)/(hBackward + hForward); - } - - return dx; -} - -DenseMatrix Function::secondOrderCentralDifference(DenseVector x) const -{ - DenseMatrix ddx(getNumVariables(), getNumVariables()); - - double h = 1e-6; // perturbation step size - double hForward = 0.5*h; - double hBackward = 0.5*h; - - for (size_t i = 0; i < getNumVariables(); ++i) - { - for (size_t j = 0; j < getNumVariables(); ++j) - { - DenseVector x0(x); - DenseVector x1(x); - DenseVector x2(x); - DenseVector x3(x); - - x0(i) = x0(i) + hForward; - x0(j) = x0(j) + hForward; - - x1(i) = x1(i) - hBackward; - x1(j) = x1(j) + hForward; - - x2(i) = x2(i) + hForward; - x2(j) = x2(j) - hBackward; - - x3(i) = x3(i) - hBackward; - x3(j) = x3(j) - hBackward; - - ddx(i, j) = (eval(x0) - eval(x1) - eval(x2) + eval(x3)) / (h * h); - } - } - - return ddx; -} - -} // namespace SPLINTER \ No newline at end of file diff --git a/splinter/function.h b/splinter/function.h deleted file mode 100644 index 0a321671af..0000000000 --- a/splinter/function.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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 SPLINTER_FUNCTION_H -#define SPLINTER_FUNCTION_H - -#include "definitions.h" -#include "saveable.h" - -namespace SPLINTER -{ - -/* - * Interface for functions - * All functions working with standard C++11 types are defined in terms of their Eigen counterparts. - * Default implementations of jacobian and hessian evaluation is using central difference. - * TODO: Remove current requirement that all functions must implement save and load! - */ -class SPLINTER_API Function : public Saveable -{ -public: - Function() - : Function(1) {} - - Function(unsigned int numVariables) - : numVariables(numVariables) {} - - virtual ~Function() {} - - /** - * Returns the function value at x - */ - virtual double eval(DenseVector x) const = 0; - - /** - * Returns the function value at x - */ - double eval(const std::vector &x) const; - - /** - * Returns the (1 x numVariables) Jacobian evaluated at x - */ - virtual DenseMatrix evalJacobian(DenseVector x) const; - - /** - * Returns the (1 x numVariables) Jacobian evaluated at x - */ - std::vector evalJacobian(const std::vector &x) const; - - /** - * Returns the (numVariables x numVariables) Hessian evaluated at x - */ - virtual DenseMatrix evalHessian(DenseVector x) const; - - /** - * Returns the (numVariables x numVariables) Hessian evaluated at x - */ - std::vector> evalHessian(const std::vector &x) const; - - /** - * Get the dimension - */ - inline unsigned int getNumVariables() const - { - return numVariables; - } - - /** - * Check input - */ - void checkInput(DenseVector x) const { - if (x.size() != (int)numVariables) - throw Exception("Function::checkInput: Wrong dimension on evaluation point x."); - } - - /** - * Returns the central difference at x - * Vector of numVariables length - */ - std::vector centralDifference(const std::vector &x) const; - DenseMatrix centralDifference(DenseVector x) const; - - std::vector> secondOrderCentralDifference(const std::vector &x) const; - DenseMatrix secondOrderCentralDifference(DenseVector x) const; - - /** - * Description of function. - */ - virtual std::string getDescription() const - { - return ""; - } - -protected: - unsigned int numVariables; // Dimension of domain (size of x) - - friend class Serializer; -}; - -} // namespace SPLINTER - -#endif // SPLINTER_FUNCTION_H \ No newline at end of file diff --git a/splinter/include/bspline.h b/splinter/include/bspline.h new file mode 100644 index 0000000000..92f83ba1ff --- /dev/null +++ b/splinter/include/bspline.h @@ -0,0 +1,175 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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 SPLINTER_BSPLINE_H +#define SPLINTER_BSPLINE_H + +#include "function.h" +#include "bspline_basis.h" +#include "data_table.h" +#include "json_parser.h" + + +namespace SPLINTER +{ + +/** + * Class that implements the multivariate tensor product B-spline + */ +class SPLINTER_API BSpline : public Function +{ +public: + + // B-spline smoothing + enum class Smoothing { + NONE, // No smoothing + IDENTITY, // Regularization term alpha*c'*I*c is added to OLS objective + PSPLINE // Second-order difference penalty alpha*Delta(c,2) is added to OLS objective + }; + + /** + * Construct B-spline from basis degree and knot vectors. Default output dimension is 1. + */ + BSpline(const std::vector °rees, const std::vector> &knot_vectors, + unsigned int dim_y = 1); + + /** + * Construct B-spline from basis degree, knot vectors and control points. + */ + BSpline(const std::vector °rees, const std::vector> &knot_vectors, + const std::vector> &control_points); + + virtual BSpline* clone() const { return new BSpline(*this); } + + /** + * Evaluation of B-spline + */ + + // Avoid name hiding + using Function::eval; + using Function::eval_jacobian; + + // Evaluate the B-spline at x. Returns vector of size (dim_y). + std::vector eval(const std::vector &x) const override; + DenseVector eval(const DenseVector &x) const override; + + // Evaluate the Jacobian at x. Returns matrix of size (dim_y, dim_x). + DenseMatrix eval_jacobian(const DenseVector &x) const override; + + // Evaluate the Hessian at x. Returns tensor of size (dim_y, dim_x, dim_x). + std::vector>> eval_hessian(const std::vector &x) const; + + // Evaluate B-spline basis functions at x. Returns vector of size (num_basis_functions). + SparseVector eval_basis(const DenseVector &x) const; + + // Evaluate Jacobian of B-spline basis functions at x. Returns vector of size (num_basis_functions, num_x). + SparseMatrix eval_basis_jacobian(const DenseVector &x) const; + + /** + * Getters + */ + DenseMatrix get_control_points() const + { + return control_points; + } + + unsigned int get_num_control_points() const + { + return (unsigned int) control_points.rows(); + } + + std::vector get_num_basis_functions_per_variable() const; + + unsigned int get_num_basis_functions() const + { + return basis.get_num_basis_functions(); + } + + unsigned int get_num_supported() const + { + return basis.num_supported(); + } + + DenseMatrix get_knot_averages() const { + return compute_knot_averages(); + }; + std::vector< std::vector> get_knot_vectors() const; + std::vector get_basis_degrees() const; + std::vector get_domain_upper_bound() const; + std::vector get_domain_lower_bound() const; + + /** + * Setters + */ + void set_control_points(const DenseMatrix &new_control_points); + + /** + * Manipulations to B-spline + */ + + // Linear transformation of control points (B-spline has affine invariance) + void linear_transform(const SparseMatrix &A); + + // Fit B-spline to sample data + BSpline& fit(const DataTable &data, Smoothing smoothing = Smoothing::NONE, double alpha = .1, + std::vector weights = std::vector()); + + // Reduce support of B-spline + void reduce_support(const std::vector &lb, const std::vector &ub, + bool regularize_knot_vectors = true); + + // Perform global knot refinement (all knots in one shabang) + void global_knot_refinement(); + + // Perform a local knot refinement at x + void local_knot_refinement(const DenseVector &x); + + // Decompose B-spline to Bezier form + void decompose_to_bezier(); + + // Insert a knot until desired knot multiplicity is obtained + void insert_knots(double tau, unsigned int dim, unsigned int multiplicity = 1); + + /** + * Save and load + */ + void to_json(const std::string &filename) const; + + static BSpline from_json(const std::string &filename); + + /** + * Helper functions + */ + void check_control_points() const; + std::string get_description() const override; + +protected: + // B-spline basis functions (multivariate) + BSplineBasis basis; + + // B-spline control points of size (num_basis_functions, dim_y). Each row is a control point. + DenseMatrix control_points; + + // Control point computations + DenseMatrix compute_knot_averages() const; + +private: + // Domain reduction + void regularize_knot_vectors(const std::vector &lb, const std::vector &ub); + bool remove_unsupported_basis_functions(const std::vector &lb, const std::vector &ub); + + // Helper functions + bool is_supported(const DenseVector &x) const; + + friend bool operator==(const BSpline &lhs, const BSpline &rhs); +}; + +} // namespace SPLINTER + +#endif // SPLINTER_BSPLINE_H diff --git a/splinter/include/bspline_basis.h b/splinter/include/bspline_basis.h new file mode 100644 index 0000000000..16b8da01eb --- /dev/null +++ b/splinter/include/bspline_basis.h @@ -0,0 +1,73 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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 SPLINTER_BSPLINE_BASIS_H +#define SPLINTER_BSPLINE_BASIS_H + +#include "definitions.h" +#include "bspline_basis_1d.h" + + +namespace SPLINTER +{ + +class BSplineBasis +{ +public: + // Constructor + BSplineBasis(std::vector degrees, const std::vector> &knot_vectors); + + // Evaluation + SparseVector eval(const DenseVector &x) const; + DenseMatrix eval_basis_jacobian_old(const DenseVector &x) const; // Deprecated + SparseMatrix eval_basis_jacobian(const DenseVector &x) const; + SparseMatrix eval_basis_jacobian2(const DenseVector &x) const; // A bit slower than evaBasisJacobianOld() + SparseMatrix eval_basis_hessian(const DenseVector &x) const; + + // Knot vector manipulation + SparseMatrix refine_knots(); + SparseMatrix refine_knots_locally(const DenseVector &x); + SparseMatrix decompose_to_bezier(); + SparseMatrix insert_knots(double tau, unsigned int dim, unsigned int multiplicity = 1); + + // Getters + BSplineBasis1D get_single_basis(unsigned int dim); + std::vector> get_knot_vectors() const; + std::vector get_knot_vector(int dim) const; + + std::vector get_basis_degrees() const; + unsigned int get_basis_degree(unsigned int dim) const; + unsigned int get_num_basis_functions() const; + unsigned int get_num_basis_functions(unsigned int dim) const; + std::vector get_num_basis_functions_target() const; + + unsigned int get_knot_multiplicity(unsigned int dim, double tau) const; + + /* + * Returns the maximum number of supported basis functions at any point in the B-spline domain + */ + unsigned int num_supported() const; + + bool inside_support(const DenseVector &x) const; + std::vector get_support_lower_bound() const; + std::vector get_support_upper_bound() const; + + // Support related + SparseMatrix reduce_support(const std::vector &lb, const std::vector &ub); + +private: + std::vector bases; + unsigned int num_variables; + + friend bool operator==(const BSplineBasis &lhs, const BSplineBasis &rhs); +}; + +} // namespace SPLINTER + +#endif // SPLINTER_BSPLINE_BASIS_H diff --git a/splinter/include/bspline_basis_1d.h b/splinter/include/bspline_basis_1d.h new file mode 100644 index 0000000000..98430ff08a --- /dev/null +++ b/splinter/include/bspline_basis_1d.h @@ -0,0 +1,101 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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 SPLINTER_BSPLINE_BASIS_1D_H +#define SPLINTER_BSPLINE_BASIS_1D_H + +#include "definitions.h" +#include "knot_vector.h" + +namespace SPLINTER +{ + +class BSplineBasis1D +{ +public: + BSplineBasis1D(unsigned int degree, const std::vector &knots); + + /** + * Evaluation of basis functions + */ + SparseVector eval(double x) const; + SparseVector eval_derivative(double x, unsigned int r) const; + SparseVector eval_first_derivative(double x) const; // TODO: Deprecated + + /** + * Knot vector related + */ + SparseMatrix refine_knots(); + SparseMatrix refine_knots_locally(double x); + SparseMatrix decompose_to_bezier(); + SparseMatrix insert_knots(double tau, unsigned int multiplicity = 1); + // bool insert_knots(SparseMatrix &A, std::vector> newKnots); // Add knots at several locations + + unsigned int knot_multiplicity(double tau) const { + // Return the number of repetitions of tau in the knot vector + return knots.multiplicity(tau); + } + + /** + * Support related + */ + double support_hack(double x) const; + bool is_supported(double x) const { + return knots.is_supported(x); + } + SparseMatrix reduce_support(double lb, double ub); + + /** + * Getters + */ + std::vector get_knot_vector() const { return knots.get_values(); } + unsigned int get_basis_degree() const { return degree; } + unsigned int get_num_basis_functions() const; + unsigned int get_num_basis_functions_target() const; + + /** + * Index getters + */ + std::vector index_supported_basis_functions(double x) const; + unsigned int index_longest_interval(const std::vector &vec) const; + + /** + * Setters + */ + void set_num_basis_functions_target(unsigned int target) + { + target_num_basis_functions = std::max(degree+1, target); + } + +private: + unsigned int degree; + KnotVector knots; + unsigned int target_num_basis_functions; + + // DeBoorCox algorithm for evaluating basis functions + double de_boor_cox(double x, unsigned int i, unsigned int k) const; + double de_boor_cox_coeff(double x, double x_min, double x_max) const; + + // Builds basis matrix for alternative evaluation of basis functions + SparseMatrix build_basis_matrix(double x, unsigned int u, unsigned int k, bool diff = false) const; + + /** + * Builds knot insertion matrix + * Implements Oslo Algorithm 1 from Lyche and Moerken (2011). Spline methods draft. + */ + SparseMatrix build_knot_insertion_matrix(const std::vector &refined_knots) const; + + // Operators + friend bool operator==(const BSplineBasis1D &lhs, const BSplineBasis1D &rhs); + friend bool operator!=(const BSplineBasis1D &lhs, const BSplineBasis1D &rhs); +}; + +} // namespace SPLINTER + +#endif // SPLINTER_BSPLINE_BASIS_1D_H diff --git a/splinter/include/bspline_builders.h b/splinter/include/bspline_builders.h new file mode 100644 index 0000000000..3ac32cc729 --- /dev/null +++ b/splinter/include/bspline_builders.h @@ -0,0 +1,63 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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 SPLINTER_BSPLINE_BUILDER_H +#define SPLINTER_BSPLINE_BUILDER_H + +#include +#include +#include + +namespace SPLINTER +{ + +/** + * Convenience functions for B-spline fitting + */ + + +/** + * Create a B-spline that interpolates the sample points. + * @param data A table of sample points on a regular grid. + * @param degree The degree of the B-spline basis functions. Default degree is 3 (cubic). + * @return A B-spline that interpolates the sample points. + */ +BSpline bspline_interpolator(const DataTable &data, unsigned int degree = 3); + + +/** + * Create a B-spline that smooths the sample points using regularization (weight decay). + * @param data A table of sample points on a regular grid. + * @param degree The degree of the B-spline basis functions. Default degree is 3 (cubic). + * @param smoothing Type of regularization to use - see BSpline::Smoothing. Default is smoothing is BSpline::PSLINE. + * @param alpha Smoothing/regularization factor. + * @param weights Sample weights. + * @return A B-spline that smooths the sample points. + */ +BSpline bspline_smoother(const DataTable &data, unsigned int degree = 3, + BSpline::Smoothing smoothing = BSpline::Smoothing::PSPLINE, double alpha = 0.1, + std::vector weights = std::vector()); + + +/** + * Create a unfitted (zero-valued) B-spline. This builder gives the user more control and allows for construction of + * B-splines with non-default knot vectors and different degrees for the univariate basis functions. + * @param data A table of sample points on a regular grid. + * @param degree The degrees of the B-spline basis functions. + * @param knot_spacing The knot spacing method used to build knot vectors. + * @param num_basis_functions The desired number of basis functions in each univariate basis (must be at least degree + 1). + * @return A B-spline that smooths the sample points. + */ +BSpline bspline_unfitted(const DataTable &data, const std::vector °rees, KnotSpacing knot_spacing, + const std::vector &num_basis_functions); + + +} // namespace SPLINTER + +#endif // SPLINTER_BSPLINE_BUILDER_H diff --git a/splinter/include/bspline_utils.h b/splinter/include/bspline_utils.h new file mode 100644 index 0000000000..98ec6ac715 --- /dev/null +++ b/splinter/include/bspline_utils.h @@ -0,0 +1,37 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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 SPLINTER_BSPLINE_UTILS_H +#define SPLINTER_BSPLINE_UTILS_H + +#include +#include + +namespace SPLINTER +{ + +// Control point computations +DenseMatrix compute_control_points(const BSpline &bspline, const DataTable &data, BSpline::Smoothing smoothing, + double alpha, std::vector weights); + +// Matrix of basis functions evaluated at samples +SparseMatrix compute_basis_function_matrix(const BSpline &bspline, const DataTable &data); + +// Stack samples in DenseMatrix +DenseMatrix stack_sample_values(const DataTable &data); + +// P-spline control point calculation +SparseMatrix compute_second_order_finite_difference_matrix(const BSpline &bspline); + +// Compute weights matrix from weight vector +SparseMatrix compute_weight_matrix(std::vector weights); + +} // namespace SPLINTER + +#endif // SPLINTER_BSPLINE_UTILS_H diff --git a/splinter/include/cinterface/cinterface.h b/splinter/include/cinterface/cinterface.h new file mode 100644 index 0000000000..d7230e22e0 --- /dev/null +++ b/splinter/include/cinterface/cinterface.h @@ -0,0 +1,399 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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 SPLINTER_CINTERFACE_H +#define SPLINTER_CINTERFACE_H + + +#ifndef SPLINTER_API +# ifdef _MSC_VER +# define SPLINTER_API __declspec(dllexport) +# else +# define SPLINTER_API +# endif +#endif + +// Pointer to C++ objects, passed into the C interface then cast to the correct type. +typedef void *splinter_obj_ptr; + + +#ifdef __cplusplus + extern "C" + { +#endif +/** + * Check if the last library call resulted in an error. + * Will reset upon call, so two consecutive calls to this function may not return the same value. + * + * @return 1 if error, 0 else. + */ +SPLINTER_API int splinter_get_error(); + +/** + * Get a string describing the error. + * + * @return Error string. + */ +SPLINTER_API const char *splinter_get_error_string(); + + + + + +/** + * Initialize a new DataTable. + * + * @return Pointer to the created DataTable. + */ +SPLINTER_API splinter_obj_ptr splinter_datatable_init(); + +/** + * Add samples that are stored in row major order to the datatable. + * + * If x0 = [x0_0, x0_1, x0_2], x1 = [x1_0, x1_1, x1_2] are two inputs with + * y0 = [y0_0, y0_1], y1 = [y1_0, y1_1], as the corresponding outputs, then + * + * xs = [x0_0, x0_1, x0_2, x1_0, x1_1, x1_2] + * x_dim = 3 + * ys = [y0_0, y0_1, y1_0, y1_1] + * y_dim = 2 + * n_samples = 2 + * + * @param datatable_ptr Pointer to the datatable. + * @param xs Pointer to the start of the inputs. + * @param x_dim The dimension of each input. + * @param ys Pointer to the start of the outputs. + * @param y_dim The dimension of each output. + * @param n_samples Number of samples to add (= xs/x_dim = ys/y_dim). + */ +SPLINTER_API void splinter_datatable_add_samples_row_major(splinter_obj_ptr datatable_ptr, + double *xs, int x_dim, + double *ys, int y_dim, + int n_samples); + +/** + * Add samples that are stored in column major order to the datatable. + * + * @param datatable_ptr Pointer to the datatable. + * @param x Pointer to the start of the samples. + * @param n_samples Number of samples to add. + * @param x_dim The dimension of each point (that is, the sample size - 1). + */ +SPLINTER_API void splinter_datatable_add_samples_col_major(splinter_obj_ptr datatable_ptr, double *x, int n_samples, int x_dim); + +/** + * Get the dimension of the domain of the samples in the datatable. + * + * @param datatable_ptr Pointer to the datatable. + * @return The dimension of the domain of the samples in the datatable. + */ +SPLINTER_API int splinter_datatable_get_dim_x(splinter_obj_ptr datatable_ptr); + +/** + * Get the dimension of the codomain of the samples in the datatable. + * + * @param datatable_ptr Pointer to the datatable. + * @return The dimension of the codomain of the samples in the datatable. + */ +SPLINTER_API int splinter_datatable_get_dim_y(splinter_obj_ptr datatable_ptr); + +/** + * Get the number of samples stored in the datatable. + * + * @param datatable_ptr Pointer to the datatable. + * @return The number of samples in the datatable. + */ +SPLINTER_API int splinter_datatable_get_num_samples(splinter_obj_ptr datatable_ptr); + +/** + * Save a DataTable to json file. + * + * @param datatable_ptr Pointer to the DataTable + * @param filename File to save the DataTable to (will be overwritten!) + */ +SPLINTER_API void splinter_datatable_to_json(splinter_obj_ptr datatable_ptr, const char *filename); + +/** + * Load a DataTable from json file. + * + * @param datatable_ptr Pointer to the DataTable + * @param filename File to save the DataTable to (will be overwritten!) + */ +SPLINTER_API splinter_obj_ptr splinter_datatable_from_json(const char *filename); + +/** + * Free the memory of a datatable. + * + * @param datatable_ptr Pointer to the datatable. + */ +SPLINTER_API void splinter_datatable_delete(splinter_obj_ptr datatable_ptr); + + + + +/** + * Construct a BSpline that interpolates the sample points. + * + * @param datatable_ptr The datatable with sample points. + * @param degree The degree of the B-spline basis functions. + * @return Pointer to the created BSpline. + */ +SPLINTER_API splinter_obj_ptr splinter_bspline_interpolator(splinter_obj_ptr datatable_ptr, int degree); + +/** + * Construct a BSpline that smooths the sample points using regularization (weight decay). + * + * @param datatable_ptr The datatable with sample points. + * @param degree The degree of the B-spline basis functions. + * @param alpha Smoothing/regularization factor. + * @return Pointer to the created BSpline. + */ +SPLINTER_API splinter_obj_ptr splinter_bspline_smoother(splinter_obj_ptr datatable_ptr, int degree, int smoothing, + double alpha, double *weights, unsigned int num_weights); + +/** + * Construct an unfitted (zero-valued) BSpline. + * + * @param datatable_ptr The datatable with sample points. + * @param degree The degree of the B-spline basis functions + * @param alpha Smoothing/regularization factor + * @return Pointer to the created BSpline. + */ +SPLINTER_API splinter_obj_ptr splinter_bspline_unfitted(splinter_obj_ptr datatable_ptr, unsigned int *degrees, + unsigned int num_degrees, int knot_spacing, + unsigned int *num_basis_functions, + unsigned int num_num_basis_functions); + + + +/** + * Construct a BSpline from parameters: coefficients, knot vectors and degrees. + * + * @param dim_x Number of inputs (variables) + * @param dim_y Number of outputs + * @param degrees B-spline degrees + * @param knot_vectors B-spline knot vectors + * @param num_knots_per_vector Number of knots per knot vector + * @param control_points B-spline control points + * @param num_control_points Number of coefficients + * @return Pointer to the created BSpline. + */ +SPLINTER_API splinter_obj_ptr splinter_bspline_from_param(unsigned int dim_x, unsigned int dim_y, unsigned int *degrees, + double *knot_vectors, unsigned int *num_knots_per_vector, + double *control_points, unsigned int num_control_points); + + +/** + * Construct a BSpline from parameters: knot vectors and degrees. Control points are set to zero. + * + * @param dim_x Number of inputs (variables) + * @param dim_y Number of outputs + * @param degrees B-spline degrees + * @param knot_vectors B-spline knot vectors + * @param num_knots_per_vector Number of knots per knot vector + * @return Pointer to the created BSpline. + */ +SPLINTER_API splinter_obj_ptr splinter_bspline_from_param_zero(unsigned int dim_x, unsigned int dim_y, + unsigned int *degrees, double *knot_vectors, + unsigned int *num_knots_per_vector); + +/** + * Get the sizes of the knot vectors that are returned by splinter_bspline_get_knot_vectors + * + * @param bspline_ptr Pointer to the BSpline + * @return Array of splinter_bspline_get_num_variables length + */ +SPLINTER_API int *splinter_bspline_get_knot_vector_sizes(splinter_obj_ptr bspline_ptr); + +/** + * Get the knot vectors of the BSpline + * Two-dimensional matrix where the rows are the knot vectors + * There are splinter_bspline_get_num_variables knot vectors + * The sizes of the knot vectors are given by splinter_bspline_get_knot_vector_sizes + * + * @param bspline_ptr Pointer to the BSpline + * @return Row major array of size stated above + */ +SPLINTER_API double *splinter_bspline_get_knot_vectors(splinter_obj_ptr bspline_ptr); + +/** + * Get the number of coefficients of the BSpline + * + * @param bspline_ptr Pointer to the BSpline + */ +SPLINTER_API int splinter_bspline_get_num_control_points(splinter_obj_ptr bspline_ptr); + +/** + * Get the control points of the BSpline + * Returns a two-dimensional matrix with + * splinter_bspline_get_num_control_points rows + * and splinter_bspline_get_num_outputs columns + * + * @param bspline_ptr Pointer to the BSpline + * @return Row major flattened array of the control points + */ +SPLINTER_API double *splinter_bspline_get_control_points(splinter_obj_ptr bspline_ptr); + +/** + * Get the knot averages of the BSpline + * Returns a two-dimensional matrix with + * splinter_bspline_get_num_control_points rows + * and splinter_bspline_get_num_variables columns + * + * @param bspline_ptr Pointer to the BSpline + * @return Row major flattened array of the knot averages + */ +SPLINTER_API double *splinter_bspline_get_knot_averages(splinter_obj_ptr bspline_ptr); + +/** + * Get the basis degrees of the BSpline + * Returns an array of size splinter_bspline_get_num_variables + * + * @param bspline_ptr Pointer to the BSpline + * @return Array of basis degrees + */ +SPLINTER_API int *splinter_bspline_get_basis_degrees(splinter_obj_ptr bspline_ptr); + +/** + * Evaluate a BSpline in one or more points. Can "batch evaluate" several points by storing the points consecutively in + * x in row major order. If function is a two-dimensional function you can evaluate the function in x0 = [0, 1] and + * x1 = [2, 3] in one function call by having x point to the start of an array of four doubles: 0 1 2 3, and x_len = 4. + * This function will then return an array of 2 doubles, the first being the result of evaluating the function in [0, 1], + * and the second being the result of evaluating the function in [2, 3]. + * + * If the function is multi-dimensional in the codomain, the results are flattened so that the result of evaluating + * the first point comes first, then the second, etc. + * + * @param bspline_ptr Pointer to the BSpline to evaluate. + * @param xs Array of doubles. Is of x_len length. + * @param x_len Length of x. + * @return Array of results corresponding to the points in x. + */ +SPLINTER_API double *splinter_bspline_eval_row_major(splinter_obj_ptr bspline_ptr, double *xs, int x_len); + +/** + * Evaluate the jacobian of a BSpline in one or more points. + * @see splinter_bspline_eval_row_major() for further explanation of the behaviour. + * + * @param bspline_ptr Pointer to the BSpline to evaluate. + * @param x Array of doubles. Is of x_len length. + * @param x_len Length of x. + * @return Flattened array of array of results corresponding to the points in x. + */ +SPLINTER_API double *splinter_bspline_eval_jacobian_row_major(splinter_obj_ptr bspline_ptr, double *x, int x_len); + +/** + * Evaluate the a BSpline in one or more points that are stored in column major order. + * @see splinter_bspline_eval_row_major() for further explanation of the behaviour. + * + * @param bspline_ptr Pointer to the BSpline to evaluate. + * @param x Array of doubles. Is of x_len length. + * @param x_len Length of x. + * @return Array of results. + */ +SPLINTER_API double *splinter_bspline_eval_col_major(splinter_obj_ptr bspline_ptr, double *x, int x_len); + +/** + * Evaluate the jacobian of a BSpline in one or more points that are stored in column major order. + * @see splinter_bspline_eval_row_major() for further explanation of the behaviour. + * + * @param bspline_ptr Pointer to the BSpline to evaluate. + * @param x Array of doubles. Is of x_len length. + * @param x_len Length of x. + * @return Flattened array of array of results corresponding to the points in x. Stored in ROW major order. + */ +SPLINTER_API double *splinter_bspline_eval_jacobian_col_major(splinter_obj_ptr bspline_ptr, double *x, int x_len); + +/** + * Get the number of inputs of a BSpline (dimension of domain). + * + * @param bspline_ptr Pointer to the BSpline. + */ +SPLINTER_API int splinter_bspline_get_dim_x(splinter_obj_ptr bspline_ptr); + +/** + * Get the number of outputs of a BSpline (dimensions of codomain). + * + * @param bspline_ptr Pointer to the BSpline. + */ +SPLINTER_API int splinter_bspline_get_dim_y(splinter_obj_ptr bspline_ptr); + +/** + * Save a BSpline to json file. + * + * @param bspline_ptr Pointer to the BSpline + * @param filename File to save the BSpline to (will be overwritten!) + */ +SPLINTER_API void splinter_bspline_to_json(splinter_obj_ptr bspline_ptr, const char *filename); + +/** + * Load a BSpline to json file. + * + * @param bspline_ptr Pointer to the BSpline + * @param filename File to save the BSpline to (will be overwritten!) + */ +SPLINTER_API splinter_obj_ptr splinter_bspline_from_json(const char *filename); + +/** + * Free the memory used by a BSpline. + * + * @param bspline_ptr Pointer to the BSpline. + */ +SPLINTER_API void splinter_bspline_delete(splinter_obj_ptr bspline_ptr); + +/** + * Insert knots at tau of multiplicity 'multiplicity' to knot vector in variable 'dim'. The B-spline is geometrically + * unaltered by the knot insertion. + * + * @param bspline_ptr Pointer to the BSpline to evaluate. + * @param tau Knot to insert + * @param dim Knot vector to insert knots + * @param multiplicity Desired multiplicity of knot + */ +SPLINTER_API void splinter_bspline_insert_knots(splinter_obj_ptr bspline_ptr, double tau, unsigned int dim, + unsigned int multiplicity); + +/** + * Insert knots until all knots have multiplicity equal to the B-spline degree. + * + * @param bspline_ptr Pointer to the BSpline to decompose to Bezier form + */ +SPLINTER_API void splinter_bspline_decompose_to_bezier_form(splinter_obj_ptr bspline_ptr); + +/** + * Make a copy of a BSpline. + * + * @param bspline_ptr + * @return The new copy + */ +SPLINTER_API splinter_obj_ptr splinter_bspline_copy(splinter_obj_ptr bspline_ptr); + +/** + * Fit BSpline to data. + * + * @param bspline_ptr The BSpline to fit. + * @param datatable_ptr The datatable with data. + * @param smoothing Smoothing type (actually an enum, see the implementation of this function for details) + * @param alpha Regularization/smoothing parameter (must be non-negative). + * @param weights Weights to apply to data points. + * @param num_weights Number of weights. + * @return Pointer to the created BSpline. + */ +SPLINTER_API splinter_obj_ptr splinter_bspline_fit(splinter_obj_ptr bspline_ptr, + splinter_obj_ptr datatable_ptr, + int smoothing, + double alpha, + double *weights, + int num_weights); + +#ifdef __cplusplus + } +#endif + +#endif // SPLINTER_CINTERFACE_H diff --git a/splinter/include/cinterface/utilities.h b/splinter/include/cinterface/utilities.h new file mode 100644 index 0000000000..c143c606b8 --- /dev/null +++ b/splinter/include/cinterface/utilities.h @@ -0,0 +1,172 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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 SPLINTER_UTILITIES_H +#define SPLINTER_UTILITIES_H + +#include "data_table.h" +#include "function.h" +#include "cinterface.h" +#include "bspline.h" +#include "knot_builders.h" +#include + + +namespace SPLINTER +{ + +// Declare the global variables for use in all source files +// All extern variables are defined in cinterface/utilities.cpp +// Keep a list of objects so we avoid performing operations on objects that don't exist +extern std::set datatables; +extern std::set bsplines; + +extern int splinter_last_func_call_error; // Tracks the success of the last function call +extern const char *splinter_error_string; // Error string (if the last function call resulted in an error) + +void set_error_string(const char *new_error_string); + +/* Check for existence of datatable_ptr, then cast splinter_obj_ptr to a DataTable * */ +DataTable *get_datatable(splinter_obj_ptr datatable_ptr); + +/* Check for existence of bspline_ptr, then cast splinter_obj_ptr to a BSpline * */ +BSpline *get_bspline(splinter_obj_ptr bspline_ptr); + +// Convert int to Smoothing +BSpline::Smoothing resolve_smoothing(int smoothing); + +// Convert int to KnotSpacing +KnotSpacing resolve_knot_spacing(int knot_spacing); + +/** + * Convert from column major to row major with point_dim number of columns. + * + * @param col_major Column major data + * @param point_dim Dimension of each point (= number of columns) + * @return col_major data stored row major. + */ +double *get_row_major(double *col_major, size_t point_dim, size_t x_len); + +/** + * Convert from standard C array to DenseVector. + * + * @param x C array to convert from. + * @param x_dim The size of x. + * @return DenseVector with the same data as x. + */ +template +DenseVector get_densevector(NUMERICAL_TYPE *x, size_t x_dim) +{ + DenseVector xvec(x_dim); + for (size_t i = 0; i < x_dim; i++) + { + xvec(i) = (double) x[i]; + } + + return xvec; +} + +/** + * Convert from DenseVector to a vector of NUMERICAL_TYPE. + * It must be possible to cast from double to NUMERICAL_TYPE. + * + * @param x DenseVector to convert from. + * @return Vector with the same data as x. + */ +template +std::vector get_vector(DenseVector x) +{ + auto vector = std::vector(x.size()); + for (size_t i = 0; i < x.size(); ++i) + { + vector.at(i) = (NUMERICAL_TYPE) x(i); + } + + return vector; +} + +/** + * Convert from pointer to NUMERICAL_TYPE to std::vector + * + * @param array Pointer to NUMERICAL_TYPE + * @param n Number of elements to copy + * @return std::vector with the same elements as in array + */ +template +std::vector get_vector(NUMERICAL_TYPE *array, int n) +{ + return std::vector(array, array + n); +} + +/** + * Convert from pointer to NUMERICAL_TYPE to std::vector> + * Number of values copied: num_per_row[0] * num_per_row[1] * ... * num_per_row[num_rows - 1] + * + * @param array Pointer to NUMERICAL_TYPE + * @param num_per_row Number of elements per row + * @param num_rows Number of rows + * @return std::vector with the same elements as in array + */ +template +std::vector> get_vector_vector(NUMERICAL_TYPE *array, unsigned int *num_per_row, + unsigned int num_rows) +{ + auto num_per_row_as_vec = std::vector(num_per_row, num_per_row + num_rows); + + auto vec_vec = std::vector>(num_rows); + + int k = 0; + for (unsigned int i = 0; i < num_rows; ++i) + { + unsigned int num_row_i = num_per_row_as_vec.at(i); + std::vector vec(num_row_i); + for (unsigned int j = 0; j < num_row_i; ++j) + { + vec.at(j) = array[k]; + k++; + } + vec_vec.at(i) = vec; + } + + return vec_vec; +} + +/** + * Convert from pointer to NUMERICAL_TYPE to std::vector> + * Number of values copied: num_per_row*num_rows + * + * @param array Pointer to NUMERICAL_TYPE + * @param num_per_row Number of elements per row (constant) + * @param num_rows Number of rows + * @return std::vector with the same elements as in array + */ +template +std::vector> get_vector_vector(NUMERICAL_TYPE *array, unsigned int num_per_row, + unsigned int num_rows) +{ + auto vec_vec = std::vector>(num_rows); + + unsigned int k = 0; + for (unsigned int i = 0; i < num_rows; ++i) + { + std::vector vec(num_per_row); + for (unsigned int j = 0; j < num_per_row; ++j) + { + vec.at(j) = array[k]; + k++; + } + vec_vec.at(i) = vec; + } + + return vec_vec; +} + +} // namespace SPLINTER + +#endif // SPLINTER_UTILITIES_H diff --git a/splinter/include/data_point.h b/splinter/include/data_point.h new file mode 100644 index 0000000000..99487754a1 --- /dev/null +++ b/splinter/include/data_point.h @@ -0,0 +1,61 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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 SPLINTER_DATA_POINT_H +#define SPLINTER_DATA_POINT_H + +#include "definitions.h" + +namespace SPLINTER +{ + +/* + * DataPoint is a class representing a data point (x, y), where y is the value obtained by sampling at a point x. + * Note that x and y may be a scalar or vector. + */ +class DataPoint +{ +public: + DataPoint(double x, double y); + DataPoint(const std::vector &x, double y); + DataPoint(double x, const std::vector &y); + DataPoint(const std::vector &x, const std::vector &y); + + /** + * Getters + */ + std::vector get_x() const { + return x; + } + + std::vector get_y() const { + return y; + } + + unsigned int get_dim_x() const { + return (unsigned int) x.size(); + } + + unsigned int get_dim_y() const { + return (unsigned int) y.size(); + } + + bool operator<(const DataPoint &rhs) const; // Returns false if the two are equal + +private: + DataPoint() {}; + + std::vector x; + std::vector y; + void set_data(const std::vector &x, const std::vector &y); +}; + +} // namespace SPLINTER + +#endif // SPLINTER_DATA_POINT_H diff --git a/splinter/include/data_table.h b/splinter/include/data_table.h new file mode 100644 index 0000000000..7d453aab3a --- /dev/null +++ b/splinter/include/data_table.h @@ -0,0 +1,117 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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 SPLINTER_DATA_TABLE_H +#define SPLINTER_DATA_TABLE_H + +#include "data_point.h" +#include +#include + + +namespace SPLINTER +{ + +/* + * DataTable is a class for storing multidimensional data samples (x, y). + * The samples are stored in a vector with properties: + * - Elements can be stored in any order (no sorted order) + * - Duplicates are allowed (DataPoint x-values determines uniqueness) + */ +class SPLINTER_API DataTable +{ +public: + DataTable() : _dim_x(1), _dim_y(1) {} + + /* + * Functions for adding a sample (x, y) + */ + void add_sample(const DataPoint &sample); + + void add_sample(std::initializer_list samples); + + template + void add_sample(Tx x, Ty y) { + return add_sample(DataPoint(x, y)); + } + + template + void add_sample(std::initializer_list x, Ty y) { + return add_sample(DataPoint(x, y)); + } + + template + void add_sample(Tx x, std::initializer_list y) { + return add_sample(DataPoint(x, y)); + } + + template + void add_sample(std::initializer_list x, std::initializer_list y) { + return add_sample(DataPoint(x, y)); + } + + /* + * Getters + */ + std::vector::const_iterator cbegin() const { + return samples.cbegin(); + } + + std::vector::const_iterator cend() const { + return samples.cend(); + } + + unsigned int get_dim_x() const { + return _dim_x; + } + + unsigned int get_dim_y() const { + return _dim_y; + } + + unsigned int get_num_samples() const { + return (unsigned int) samples.size(); + } + + const std::vector& get_samples() const { + return samples; + } + + std::vector> get_table_x() const; + + std::vector> get_table_y() const; + + /** + * Save and load + */ + void to_json(const std::string &filename) const { + SPLINTER::datatable_to_json(*this, filename); + } + + static DataTable from_json(const std::string &filename) { + return SPLINTER::datatable_from_json(filename); + } + + /** + * Utilities + */ + bool is_grid_complete() const; + +private: + unsigned int _dim_x; + unsigned int _dim_y; + std::vector samples; + + friend bool operator==(const DataTable &lhs, const DataTable &rhs); +// friend void datatable_to_json(const DataTable &data, const std::string &filename); +}; + +} // namespace SPLINTER + +#endif // SPLINTER_DATA_TABLE_H diff --git a/splinter/definitions.h b/splinter/include/definitions.h similarity index 71% rename from splinter/definitions.h rename to splinter/include/definitions.h index 068902df52..3f96504fe9 100644 --- a/splinter/definitions.h +++ b/splinter/include/definitions.h @@ -13,7 +13,7 @@ #ifndef SPLINTER_API # ifdef _MSC_VER -# define SPLINTER_API //__stdcall//__declspec(dllexport) +# define SPLINTER_API __declspec(dllexport) # else # define SPLINTER_API # endif @@ -30,34 +30,10 @@ # include #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push -// fails CentOS 7 #pragma GCC diagnostic ignored "-Wignored-attributes" +#pragma GCC diagnostic ignored "-Wignored-attributes" #endif -//# include -#include "Core" -#include "LU" -#include "Cholesky" -#include "QR" -#include "SVD" -#include "Geometry" -#include "Eigenvalues" -//# include - -#include "SparseCore" -#include "OrderingMethods" -#include "SparseCholesky" -#include "SparseLU" -#include "SparseQR" -#include "IterativeLinearSolvers" - - -#include -#include -#include -#include -#include - - - +# include +# include #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif diff --git a/splinter/include/function.h b/splinter/include/function.h new file mode 100644 index 0000000000..b4ce0e977a --- /dev/null +++ b/splinter/include/function.h @@ -0,0 +1,95 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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 SPLINTER_FUNCTION_H +#define SPLINTER_FUNCTION_H + +#include "definitions.h" + +namespace SPLINTER +{ + +/* + * Interface for functions f : R^m -> R^n + * All functions working with standard C++11 types are defined in terms of their Eigen counterparts. + * Default implementations of Jacobian uses central differences. + */ +class SPLINTER_API Function +{ +public: + Function() + : Function(1, 1) {} + + Function(unsigned int m, unsigned int n) + : dim_x(m), dim_y(n) {} + + virtual ~Function() {} + + /** + * Returns the (dimY) function values at x + */ + virtual std::vector eval(const std::vector &x) const = 0; + + virtual DenseVector eval(const DenseVector &x) const; + + /** + * Returns the (dimY x dimX) Jacobian evaluated at x + */ + virtual DenseMatrix eval_jacobian(const DenseVector &x) const; + + /** + * Returns the (dimY x dimX) Jacobian evaluated at x + */ + std::vector> eval_jacobian(const std::vector &x) const; + + /** + * Get dimensions + */ + inline unsigned int get_dim_x() const + { + return dim_x; + } + + inline unsigned int get_dim_y() const + { + return dim_y; + } + + /** + * Check input + */ + void check_input(const std::vector &x) const { + if (x.size() != dim_x) + throw Exception("Function::check_input: Wrong dimension on evaluation point x."); + } + + void check_input(const DenseVector &x) const; + + /** + * Returns the central difference at x + */ + DenseMatrix central_difference(const DenseVector &x) const; + + /** + * Description of function. + */ + virtual std::string get_description() const + { + return ""; + } + +protected: + unsigned int dim_x; // Dimension of domain (size of x) + unsigned int dim_y; // Dimension of codomain (size of y) + +}; + +} // namespace SPLINTER + +#endif // SPLINTER_FUNCTION_H \ No newline at end of file diff --git a/splinter/include/json.h b/splinter/include/json.h new file mode 100644 index 0000000000..b7e7952b82 --- /dev/null +++ b/splinter/include/json.h @@ -0,0 +1,17170 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.1.0 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +Copyright (c) 2013-2018 Niels Lohmann . + +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 NLOHMANN_JSON_HPP +#define NLOHMANN_JSON_HPP + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 1 +#define NLOHMANN_JSON_VERSION_PATCH 0 + +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // iterator_traits, random_access_iterator_tag +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap + +// #include +#ifndef NLOHMANN_JSON_FWD_HPP +#define NLOHMANN_JSON_FWD_HPP + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = +std::map, +template class ArrayType = std::vector, +class StringType = std::string, class BooleanType = bool, +class NumberIntegerType = std::int64_t, +class NumberUnsignedType = std::uint64_t, +class NumberFloatType = double, +template class AllocatorType = std::allocator, +template class JSONSerializer = +adl_serializer> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +template +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} + +#endif + +// #include + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if defined(__clang__) +#if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 +#error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" +#endif +#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) +#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 +#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" +#endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) +#define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define JSON_DEPRECATED __declspec(deprecated) +#else +#define JSON_DEPRECATED +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) +#define JSON_THROW(exception) throw exception +#define JSON_TRY try +#define JSON_CATCH(exception) catch(exception) +#else +#define JSON_THROW(exception) std::abort() +#define JSON_TRY if(true) +#define JSON_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) +#undef JSON_THROW +#define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) +#undef JSON_TRY +#define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) +#undef JSON_CATCH +#define JSON_CATCH JSON_CATCH_USER +#endif + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) +#define JSON_LIKELY(x) __builtin_expect(!!(x), 1) +#define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define JSON_LIKELY(x) x +#define JSON_UNLIKELY(x) x +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 +#define JSON_HAS_CPP_17 +#define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) +#define JSON_HAS_CPP_14 +#endif + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +/*! +@brief Helper to determine whether there's a key_type for T. + +This helper is used to tell associative containers apart from other containers +such as sequence containers. For instance, `std::map` passes the test as it +contains a `mapped_type`, whereas `std::vector` fails the test. + +@sa http://stackoverflow.com/a/7728728/266378 +@since version 1.0.0, overworked in version 2.0.6 +*/ +#define NLOHMANN_JSON_HAS_HELPER(type) \ + template struct has_##type { \ + private: \ + template \ + static int detect(U &&); \ + static void detect(...); \ + public: \ + static constexpr bool value = \ + std::is_integral()))>::value; \ + } + +// #include + + +#include // not +#include // size_t +#include // numeric_limits +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // declval + +// #include + +// #include + + +namespace nlohmann +{ +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ +///////////// +// helpers // +///////////// + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ +using type = index_sequence; +using value_type = std::size_t; +static constexpr std::size_t size() noexcept +{ +return sizeof...(Ints); +} +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> +: index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence +: merge_and_renumber < typename make_index_sequence < N / 2 >::type, +typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +/* +Implementation of two C++17 constructs: conjunction, negation. This is needed +to avoid evaluating all the traits in a condition + +For example: not std::is_same::value and has_value_type::value +will not compile when T = void (on MSVC at least). Whereas +conjunction>, has_value_type>::value will +stop evaluating if negation<...>::value == false + +Please note that those constructs must be used with caution, since symbols can +become very long quickly (which can slow down compilation and cause MSVC +internal compiler errors). Only use it when you have to (see example ahead). +*/ +template struct conjunction : std::true_type {}; +template struct conjunction : B1 {}; +template +struct conjunction : std::conditional, B1>::type {}; + +template struct negation : std::integral_constant {}; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +//////////////////////// +// has_/is_ functions // +//////////////////////// + +// source: https://stackoverflow.com/a/37193089/4116453 + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +NLOHMANN_JSON_HAS_HELPER(mapped_type); +NLOHMANN_JSON_HAS_HELPER(key_type); +NLOHMANN_JSON_HAS_HELPER(value_type); +NLOHMANN_JSON_HAS_HELPER(iterator); + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl +{ +static constexpr auto value = +std::is_constructible::value and +std::is_constructible::value; +}; + +template +struct is_compatible_object_type +{ +static auto constexpr value = is_compatible_object_type_impl < +conjunction>, +has_mapped_type, +has_key_type>::value, +typename BasicJsonType::object_t, CompatibleObjectType >::value; +}; + +template +struct is_basic_json_nested_type +{ +static auto constexpr value = std::is_same::value or +std::is_same::value or +std::is_same::value or +std::is_same::value; +}; + +template +struct is_compatible_array_type +{ +static auto constexpr value = +conjunction>, +negation>, +negation>, +negation>, +has_value_type, +has_iterator>::value; +}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl +{ +// is there an assert somewhere on overflows? +using RealLimits = std::numeric_limits; +using CompatibleLimits = std::numeric_limits; + +static constexpr auto value = +std::is_constructible::value and +CompatibleLimits::is_integer and +RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type +{ +static constexpr auto value = +is_compatible_integer_type_impl < +std::is_integral::value and +not std::is_same::value, +RealIntegerType, CompatibleNumberIntegerType > ::value; +}; + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json +{ +private: +// also check the return type of from_json +template::from_json( +std::declval(), std::declval()))>::value>> +static int detect(U&&); +static void detect(...); + +public: +static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json +{ +private: +template < +typename U, +typename = enable_if_t::from_json(std::declval()))>::value >> +static int detect(U&&); +static void detect(...); + +public: +static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +template +struct has_to_json +{ +private: +template::to_json( +std::declval(), std::declval()))> +static int detect(U&&); +static void detect(...); + +public: +static constexpr bool value = std::is_integral>()))>::value; +}; + +template +struct is_compatible_complete_type +{ +static constexpr bool value = +not std::is_base_of::value and +not std::is_same::value and +not is_basic_json_nested_type::value and +has_to_json::value; +}; + +template +struct is_compatible_type +: conjunction, +is_compatible_complete_type> +{ +}; + +// taken from ranges-v3 +template +struct static_const +{ +static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} +} + +// #include + + +#include // exception +#include // runtime_error +#include // to_string + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ +public: +/// returns the explanatory string +const char* what() const noexcept override +{ +return m.what(); +} + +/// the id of the exception +const int id; + +protected: +exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + +static std::string name(const std::string& ename, int id_) +{ +return "[json.exception." + ename + "." + std::to_string(id_) + "] "; +} + +private: +/// an exception object as storage for error messages +std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ +public: +/*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] byte_ the byte index where the error occurred (or 0 if the + position cannot be determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ +static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) +{ +std::string w = exception::name("parse_error", id_) + "parse error" + +(byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + +": " + what_arg; +return parse_error(id_, byte_, w.c_str()); +} + +/*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ +const std::size_t byte; + +private: +parse_error(int id_, std::size_t byte_, const char* what_arg) +: exception(id_, what_arg), byte(byte_) {} +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ +public: +static invalid_iterator create(int id_, const std::string& what_arg) +{ +std::string w = exception::name("invalid_iterator", id_) + what_arg; +return invalid_iterator(id_, w.c_str()); +} + +private: +invalid_iterator(int id_, const char* what_arg) +: exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ +public: +static type_error create(int id_, const std::string& what_arg) +{ +std::string w = exception::name("type_error", id_) + what_arg; +return type_error(id_, w.c_str()); +} + +private: +type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON only supports integers numbers up to 9223372036854775807. | + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ +public: +static out_of_range create(int id_, const std::string& what_arg) +{ +std::string w = exception::name("out_of_range", id_) + what_arg; +return out_of_range(id_, w.c_str()); +} + +private: +out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ +public: +static other_error create(int id_, const std::string& what_arg) +{ +std::string w = exception::name("other_error", id_) + what_arg; +return other_error(id_, w.c_str()); +} + +private: +other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} +} + +// #include + + +#include // array +#include // and +#include // size_t +#include // uint8_t + +namespace nlohmann +{ +namespace detail +{ +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ +null, ///< null value +object, ///< object (unordered set of name/value pairs) +array, ///< array (ordered collection of values) +string, ///< string value +boolean, ///< boolean value +number_integer, ///< number value (signed integer) +number_unsigned, ///< number value (unsigned integer) +number_float, ///< number value (floating-point) +discarded ///< discarded by the the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string +- furthermore, each type is not smaller than itself +- discarded values are not comparable + +@since version 1.0.0 +*/ +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ +static constexpr std::array order = {{ +0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, +1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ +} +}; + +const auto l_index = static_cast(lhs); +const auto r_index = static_cast(rhs); +return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; +} +} +} + +// #include + + +#include // transform +#include // array +#include // and, not +#include // forward_list +#include // inserter, front_inserter, end +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // pair, declval +#include // valarray + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +// overloads for basic_json template parameters +template::value and +not std::is_same::value, +int> = 0> +void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) +{ +switch (static_cast(j)) +{ +case value_t::number_unsigned: +{ +val = static_cast(*j.template get_ptr()); +break; +} +case value_t::number_integer: +{ +val = static_cast(*j.template get_ptr()); +break; +} +case value_t::number_float: +{ +val = static_cast(*j.template get_ptr()); +break; +} + +default: +JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); +} +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) +{ +if (JSON_UNLIKELY(not j.is_boolean())) +{ +JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); +} +b = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) +{ +if (JSON_UNLIKELY(not j.is_string())) +{ +JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); +} +s = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) +{ +get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) +{ +get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) +{ +get_arithmetic_value(j, val); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, EnumType& e) +{ +typename std::underlying_type::type val; +get_arithmetic_value(j, val); +e = static_cast(val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) +{ +if (JSON_UNLIKELY(not j.is_array())) +{ +JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); +} +arr = *j.template get_ptr(); +} + +// forward_list doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::forward_list& l) +{ +if (JSON_UNLIKELY(not j.is_array())) +{ +JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); +} +std::transform(j.rbegin(), j.rend(), +std::front_inserter(l), [](const BasicJsonType & i) +{ +return i.template get(); +}); +} + +// valarray doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::valarray& l) +{ +if (JSON_UNLIKELY(not j.is_array())) +{ +JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); +} +l.resize(j.size()); +std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); +} + +template +void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) +{ +using std::end; + +std::transform(j.begin(), j.end(), +std::inserter(arr, end(arr)), [](const BasicJsonType & i) +{ +// get() returns *this, this won't call a from_json +// method when value_type is BasicJsonType +return i.template get(); +}); +} + +template +auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) +-> decltype( +arr.reserve(std::declval()), +void()) +{ +using std::end; + +arr.reserve(j.size()); +std::transform(j.begin(), j.end(), +std::inserter(arr, end(arr)), [](const BasicJsonType & i) +{ +// get() returns *this, this won't call a from_json +// method when value_type is BasicJsonType +return i.template get(); +}); +} + +template +void from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) +{ +for (std::size_t i = 0; i < N; ++i) +{ +arr[i] = j.at(i).template get(); +} +} + +template::value and +std::is_convertible::value and +not std::is_same::value, int> = 0> +void from_json(const BasicJsonType& j, CompatibleArrayType& arr) +{ +if (JSON_UNLIKELY(not j.is_array())) +{ +JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); +} + +from_json_array_impl(j, arr, priority_tag<2> {}); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, CompatibleObjectType& obj) +{ +if (JSON_UNLIKELY(not j.is_object())) +{ +JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); +} + +auto inner_object = j.template get_ptr(); +using value_type = typename CompatibleObjectType::value_type; +std::transform( +inner_object->begin(), inner_object->end(), +std::inserter(obj, obj.begin()), +[](typename BasicJsonType::object_t::value_type const & p) +{ +return value_type(p.first, p.second.template get()); +}); +} + +// overload for arithmetic types, not chosen for basic_json template arguments +// (BooleanType, etc..); note: Is it really necessary to provide explicit +// overloads for boolean_t etc. in case of a custom BooleanType which is not +// an arithmetic type? +template::value and +not std::is_same::value and +not std::is_same::value and +not std::is_same::value and +not std::is_same::value, +int> = 0> +void from_json(const BasicJsonType& j, ArithmeticType& val) +{ +switch (static_cast(j)) +{ +case value_t::number_unsigned: +{ +val = static_cast(*j.template get_ptr()); +break; +} +case value_t::number_integer: +{ +val = static_cast(*j.template get_ptr()); +break; +} +case value_t::number_float: +{ +val = static_cast(*j.template get_ptr()); +break; +} +case value_t::boolean: +{ +val = static_cast(*j.template get_ptr()); +break; +} + +default: +JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); +} +} + +template +void from_json(const BasicJsonType& j, std::pair& p) +{ +p = {j.at(0).template get(), j.at(1).template get()}; +} + +template +void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) +{ +t = std::make_tuple(j.at(Idx).template get::type>()...); +} + +template +void from_json(const BasicJsonType& j, std::tuple& t) +{ +from_json_tuple_impl(j, t, index_sequence_for {}); +} + +struct from_json_fn +{ +private: +template +auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const +noexcept(noexcept(from_json(j, val))) +-> decltype(from_json(j, val), void()) +{ +return from_json(j, val); +} + +template +void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept +{ +static_assert(sizeof(BasicJsonType) == 0, +"could not find from_json() method in T's namespace"); +#ifdef _MSC_VER +// MSVC does not show a stacktrace for the above assert +using decayed = uncvref_t; +static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, +"forcing MSVC stacktrace to show which T we're talking about."); +#endif +} + +public: +template +void operator()(const BasicJsonType& j, T& val) const +noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) +{ +return call(j, val, priority_tag<1> {}); +} +}; +} + +/// namespace to hold default `from_json` function +/// to see why this is required: +/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html +namespace +{ +constexpr const auto& from_json = detail::static_const::value; +} +} + +// #include + + +#include // or, and, not +#include // begin, end +#include // tuple, get +#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type +#include // move, forward, declval, pair +#include // valarray +#include // vector + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +////////////////// +// constructors // +////////////////// + +template struct external_constructor; + +template<> +struct external_constructor +{ +template +static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept +{ +j.m_type = value_t::boolean; +j.m_value = b; +j.assert_invariant(); +} +}; + +template<> +struct external_constructor +{ +template +static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) +{ +j.m_type = value_t::string; +j.m_value = s; +j.assert_invariant(); +} + +template +static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) +{ +j.m_type = value_t::string; +j.m_value = std::move(s); +j.assert_invariant(); +} +}; + +template<> +struct external_constructor +{ +template +static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept +{ +j.m_type = value_t::number_float; +j.m_value = val; +j.assert_invariant(); +} +}; + +template<> +struct external_constructor +{ +template +static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept +{ +j.m_type = value_t::number_unsigned; +j.m_value = val; +j.assert_invariant(); +} +}; + +template<> +struct external_constructor +{ +template +static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept +{ +j.m_type = value_t::number_integer; +j.m_value = val; +j.assert_invariant(); +} +}; + +template<> +struct external_constructor +{ +template +static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) +{ +j.m_type = value_t::array; +j.m_value = arr; +j.assert_invariant(); +} + +template +static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) +{ +j.m_type = value_t::array; +j.m_value = std::move(arr); +j.assert_invariant(); +} + +template::value, +int> = 0> +static void construct(BasicJsonType& j, const CompatibleArrayType& arr) +{ +using std::begin; +using std::end; +j.m_type = value_t::array; +j.m_value.array = j.template create(begin(arr), end(arr)); +j.assert_invariant(); +} + +template +static void construct(BasicJsonType& j, const std::vector& arr) +{ +j.m_type = value_t::array; +j.m_value = value_t::array; +j.m_value.array->reserve(arr.size()); +for (const bool x : arr) +{ +j.m_value.array->push_back(x); +} +j.assert_invariant(); +} + +template::value, int> = 0> +static void construct(BasicJsonType& j, const std::valarray& arr) +{ +j.m_type = value_t::array; +j.m_value = value_t::array; +j.m_value.array->resize(arr.size()); +std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); +j.assert_invariant(); +} +}; + +template<> +struct external_constructor +{ +template +static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) +{ +j.m_type = value_t::object; +j.m_value = obj; +j.assert_invariant(); +} + +template +static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) +{ +j.m_type = value_t::object; +j.m_value = std::move(obj); +j.assert_invariant(); +} + +template::value, int> = 0> +static void construct(BasicJsonType& j, const CompatibleObjectType& obj) +{ +using std::begin; +using std::end; + +j.m_type = value_t::object; +j.m_value.object = j.template create(begin(obj), end(obj)); +j.assert_invariant(); +} +}; + +///////////// +// to_json // +///////////// + +template::value, int> = 0> +void to_json(BasicJsonType& j, T b) noexcept +{ +external_constructor::construct(j, b); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleString& s) +{ +external_constructor::construct(j, s); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) +{ +external_constructor::construct(j, std::move(s)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, FloatType val) noexcept +{ +external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept +{ +external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept +{ +external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, EnumType e) noexcept +{ +using underlying_type = typename std::underlying_type::type; +external_constructor::construct(j, static_cast(e)); +} + +template +void to_json(BasicJsonType& j, const std::vector& e) +{ +external_constructor::construct(j, e); +} + +template::value or +std::is_same::value, +int> = 0> +void to_json(BasicJsonType& j, const CompatibleArrayType& arr) +{ +external_constructor::construct(j, arr); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, std::valarray arr) +{ +external_constructor::construct(j, std::move(arr)); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) +{ +external_constructor::construct(j, std::move(arr)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleObjectType& obj) +{ +external_constructor::construct(j, obj); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) +{ +external_constructor::construct(j, std::move(obj)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, T (&arr)[N]) +{ +external_constructor::construct(j, arr); +} + +template +void to_json(BasicJsonType& j, const std::pair& p) +{ +j = {p.first, p.second}; +} + +template +void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) +{ +j = {std::get(t)...}; +} + +template +void to_json(BasicJsonType& j, const std::tuple& t) +{ +to_json_tuple_impl(j, t, index_sequence_for {}); +} + +struct to_json_fn +{ +private: +template +auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward(val)))) +-> decltype(to_json(j, std::forward(val)), void()) +{ +return to_json(j, std::forward(val)); +} + +template +void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept +{ +static_assert(sizeof(BasicJsonType) == 0, +"could not find to_json() method in T's namespace"); + +#ifdef _MSC_VER +// MSVC does not show a stacktrace for the above assert +using decayed = uncvref_t; +static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, +"forcing MSVC stacktrace to show which T we're talking about."); +#endif +} + +public: +template +void operator()(BasicJsonType& j, T&& val) const +noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1> {}))) +{ +return call(j, std::forward(val), priority_tag<1> {}); +} +}; +} + +/// namespace to hold default `to_json` function +namespace +{ +constexpr const auto& to_json = detail::static_const::value; +} +} + +// #include + + +#include // min +#include // array +#include // assert +#include // size_t +#include // strlen +#include // streamsize, streamoff, streampos +#include // istream +#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next +#include // shared_ptr, make_shared, addressof +#include // accumulate +#include // string, char_traits +#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer +#include // pair, declval + +// #include + + +namespace nlohmann +{ +namespace detail +{ +//////////////////// +// input adapters // +//////////////////// + +/*! +@brief abstract input adapter interface + +Produces a stream of std::char_traits::int_type characters from a +std::istream, a buffer, or some other input type. Accepts the return of exactly +one non-EOF character for future input. The int_type characters returned +consist of all valid char values as positive values (typically unsigned char), +plus an EOF value outside that range, specified by the value of the function +std::char_traits::eof(). This value is typically -1, but could be any +arbitrary value which is not a valid char value. +*/ +struct input_adapter_protocol +{ +/// get a character [0,255] or std::char_traits::eof(). +virtual std::char_traits::int_type get_character() = 0; +/// restore the last non-eof() character to input +virtual void unget_character() = 0; +virtual ~input_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +using input_adapter_t = std::shared_ptr; + +/*! +Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at +beginning of input. Does not support changing the underlying std::streambuf +in mid-input. Maintains underlying std::istream and std::streambuf to support +subsequent use of standard std::istream operations to process any input +characters following those used in parsing the JSON input. Clears the +std::istream flags; any input errors (e.g., EOF) will be detected by the first +subsequent call for input from the std::istream. +*/ +class input_stream_adapter : public input_adapter_protocol +{ +public: +~input_stream_adapter() override +{ +// clear stream flags; we use underlying streambuf I/O, do not +// maintain ifstream flags +is.clear(); +} + +explicit input_stream_adapter(std::istream& i) +: is(i), sb(*i.rdbuf()) +{ +// skip byte order mark +std::char_traits::int_type c; +if ((c = get_character()) == 0xEF) +{ +if ((c = get_character()) == 0xBB) +{ +if ((c = get_character()) == 0xBF) +{ +return; // Ignore BOM +} +else if (c != std::char_traits::eof()) +{ +is.unget(); +} +is.putback('\xBB'); +} +else if (c != std::char_traits::eof()) +{ +is.unget(); +} +is.putback('\xEF'); +} +else if (c != std::char_traits::eof()) +{ +is.unget(); // no byte order mark; process as usual +} +} + +// delete because of pointer members +input_stream_adapter(const input_stream_adapter&) = delete; +input_stream_adapter& operator=(input_stream_adapter&) = delete; + +// std::istream/std::streambuf use std::char_traits::to_int_type, to +// ensure that std::char_traits::eof() and the character 0xFF do not +// end up as the same value, eg. 0xFFFFFFFF. +std::char_traits::int_type get_character() override +{ +return sb.sbumpc(); +} + +void unget_character() override +{ +sb.sungetc(); // is.unget() avoided for performance +} + +private: +/// the associated input stream +std::istream& is; +std::streambuf& sb; +}; + +/// input adapter for buffer input +class input_buffer_adapter : public input_adapter_protocol +{ +public: +input_buffer_adapter(const char* b, const std::size_t l) +: cursor(b), limit(b + l), start(b) +{ +// skip byte order mark +if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF') +{ +cursor += 3; +} +} + +// delete because of pointer members +input_buffer_adapter(const input_buffer_adapter&) = delete; +input_buffer_adapter& operator=(input_buffer_adapter&) = delete; + +std::char_traits::int_type get_character() noexcept override +{ +if (JSON_LIKELY(cursor < limit)) +{ +return std::char_traits::to_int_type(*(cursor++)); +} + +return std::char_traits::eof(); +} + +void unget_character() noexcept override +{ +if (JSON_LIKELY(cursor > start)) +{ +--cursor; +} +} + +private: +/// pointer to the current character +const char* cursor; +/// pointer past the last character +const char* limit; +/// pointer to the first character +const char* start; +}; + +class input_adapter +{ +public: +// native support + +/// input adapter for input stream +input_adapter(std::istream& i) +: ia(std::make_shared(i)) {} + +/// input adapter for input stream +input_adapter(std::istream&& i) +: ia(std::make_shared(i)) {} + +/// input adapter for buffer +template::value and +std::is_integral::type>::value and +sizeof(typename std::remove_pointer::type) == 1, +int>::type = 0> +input_adapter(CharT b, std::size_t l) +: ia(std::make_shared(reinterpret_cast(b), l)) {} + +// derived support + +/// input adapter for string literal +template::value and +std::is_integral::type>::value and +sizeof(typename std::remove_pointer::type) == 1, +int>::type = 0> +input_adapter(CharT b) +: input_adapter(reinterpret_cast(b), +std::strlen(reinterpret_cast(b))) {} + +/// input adapter for iterator range with contiguous storage +template::iterator_category, std::random_access_iterator_tag>::value, +int>::type = 0> +input_adapter(IteratorType first, IteratorType last) +{ +// assertion to check that the iterator range is indeed contiguous, +// see http://stackoverflow.com/a/35008842/266378 for more discussion +assert(std::accumulate( +first, last, std::pair(true, 0), +[&first](std::pair res, decltype(*first) val) +{ +res.first &= (val == *(std::next(std::addressof(*first), res.second++))); +return res; +}).first); + +// assertion to check that each element is 1 byte long +static_assert( +sizeof(typename std::iterator_traits::value_type) == 1, +"each element in the iterator range must have the size of 1 byte"); + +const auto len = static_cast(std::distance(first, last)); +if (JSON_LIKELY(len > 0)) +{ +// there is at least one element: use the address of first +ia = std::make_shared(reinterpret_cast(&(*first)), len); +} +else +{ +// the address of first cannot be used: use nullptr +ia = std::make_shared(nullptr, len); +} +} + +/// input adapter for array +template +input_adapter(T (&array)[N]) +: input_adapter(std::begin(array), std::end(array)) {} + +/// input adapter for contiguous container +template::value and +std::is_base_of()))>::iterator_category>::value, +int>::type = 0> +input_adapter(const ContiguousContainer& c) +: input_adapter(std::begin(c), std::end(c)) {} + +operator input_adapter_t() +{ +return ia; +} + +private: +/// the actual adapter +input_adapter_t ia = nullptr; +}; +} +} + +// #include + + +#include // localeconv +#include // size_t +#include // strtof, strtod, strtold, strtoll, strtoull +#include // initializer_list +#include // hex, uppercase +#include // setw, setfill +#include // stringstream +#include // char_traits, string +#include // vector + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////// +// lexer // +/////////// + +/*! +@brief lexical analysis + +This class organizes the lexical analysis during JSON deserialization. +*/ +template +class lexer +{ +using number_integer_t = typename BasicJsonType::number_integer_t; +using number_unsigned_t = typename BasicJsonType::number_unsigned_t; +using number_float_t = typename BasicJsonType::number_float_t; + +public: +/// token types for the parser +enum class token_type +{ +uninitialized, ///< indicating the scanner is uninitialized +literal_true, ///< the `true` literal +literal_false, ///< the `false` literal +literal_null, ///< the `null` literal +value_string, ///< a string -- use get_string() for actual value +value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value +value_integer, ///< a signed integer -- use get_number_integer() for actual value +value_float, ///< an floating point number -- use get_number_float() for actual value +begin_array, ///< the character for array begin `[` +begin_object, ///< the character for object begin `{` +end_array, ///< the character for array end `]` +end_object, ///< the character for object end `}` +name_separator, ///< the name separator `:` +value_separator, ///< the value separator `,` +parse_error, ///< indicating a parse error +end_of_input, ///< indicating the end of the input buffer +literal_or_value ///< a literal or the begin of a value (only for diagnostics) +}; + +/// return name of values of type token_type (only used for errors) +static const char* token_type_name(const token_type t) noexcept +{ +switch (t) +{ +case token_type::uninitialized: +return ""; +case token_type::literal_true: +return "true literal"; +case token_type::literal_false: +return "false literal"; +case token_type::literal_null: +return "null literal"; +case token_type::value_string: +return "string literal"; +case lexer::token_type::value_unsigned: +case lexer::token_type::value_integer: +case lexer::token_type::value_float: +return "number literal"; +case token_type::begin_array: +return "'['"; +case token_type::begin_object: +return "'{'"; +case token_type::end_array: +return "']'"; +case token_type::end_object: +return "'}'"; +case token_type::name_separator: +return "':'"; +case token_type::value_separator: +return "','"; +case token_type::parse_error: +return ""; +case token_type::end_of_input: +return "end of input"; +case token_type::literal_or_value: +return "'[', '{', or a literal"; +default: // catch non-enum values +return "unknown token"; // LCOV_EXCL_LINE +} +} + +explicit lexer(detail::input_adapter_t adapter) +: ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} + +// delete because of pointer members +lexer(const lexer&) = delete; +lexer& operator=(lexer&) = delete; + +private: +///////////////////// +// locales +///////////////////// + +/// return the locale-dependent decimal point +static char get_decimal_point() noexcept +{ +const auto loc = localeconv(); +assert(loc != nullptr); +return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); +} + +///////////////////// +// scan functions +///////////////////// + +/*! + @brief get codepoint from 4 hex characters following `\u` + + For input "\u c1 c2 c3 c4" the codepoint is: + (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 + = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) + + Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' + must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The + conversion is done by subtracting the offset (0x30, 0x37, and 0x57) + between the ASCII value of the character and the desired integer value. + + @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or + non-hex character) + */ +int get_codepoint() +{ +// this function only makes sense after reading `\u` +assert(current == 'u'); +int codepoint = 0; + +const auto factors = { 12, 8, 4, 0 }; +for (const auto factor : factors) +{ +get(); + +if (current >= '0' and current <= '9') +{ +codepoint += ((current - 0x30) << factor); +} +else if (current >= 'A' and current <= 'F') +{ +codepoint += ((current - 0x37) << factor); +} +else if (current >= 'a' and current <= 'f') +{ +codepoint += ((current - 0x57) << factor); +} +else +{ +return -1; +} +} + +assert(0x0000 <= codepoint and codepoint <= 0xFFFF); +return codepoint; +} + +/*! + @brief check if the next byte(s) are inside a given range + + Adds the current byte and, for each passed range, reads a new byte and + checks if it is inside the range. If a violation was detected, set up an + error message and return false. Otherwise, return true. + + @param[in] ranges list of integers; interpreted as list of pairs of + inclusive lower and upper bound, respectively + + @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, + 1, 2, or 3 pairs. This precondition is enforced by an assertion. + + @return true if and only if no range violation was detected + */ +bool next_byte_in_range(std::initializer_list ranges) +{ +assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); +add(current); + +for (auto range = ranges.begin(); range != ranges.end(); ++range) +{ +get(); +if (JSON_LIKELY(*range <= current and current <= *(++range))) +{ +add(current); +} +else +{ +error_message = "invalid string: ill-formed UTF-8 byte"; +return false; +} +} + +return true; +} + +/*! + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 7159. While + scanning, bytes are escaped and copied into buffer token_buffer. Then the + function returns successfully, token_buffer is *not* null-terminated (as it + may contain \0 bytes), and token_buffer.size() is the number of bytes in the + string. + + @return token_type::value_string if string could be successfully scanned, + token_type::parse_error otherwise + + @note In case of errors, variable error_message contains a textual + description. + */ +token_type scan_string() +{ +// reset token_buffer (ignore opening quote) +reset(); + +// we entered the function by reading an open quote +assert(current == '\"'); + +while (true) +{ +// get next character +switch (get()) +{ +// end of file while parsing string +case std::char_traits::eof(): +{ +error_message = "invalid string: missing closing quote"; +return token_type::parse_error; +} + +// closing quote +case '\"': +{ +return token_type::value_string; +} + +// escapes +case '\\': +{ +switch (get()) +{ +// quotation mark +case '\"': +add('\"'); +break; +// reverse solidus +case '\\': +add('\\'); +break; +// solidus +case '/': +add('/'); +break; +// backspace +case 'b': +add('\b'); +break; +// form feed +case 'f': +add('\f'); +break; +// line feed +case 'n': +add('\n'); +break; +// carriage return +case 'r': +add('\r'); +break; +// tab +case 't': +add('\t'); +break; + +// unicode escapes +case 'u': +{ +const int codepoint1 = get_codepoint(); +int codepoint = codepoint1; // start with codepoint1 + +if (JSON_UNLIKELY(codepoint1 == -1)) +{ +error_message = "invalid string: '\\u' must be followed by 4 hex digits"; +return token_type::parse_error; +} + +// check if code point is a high surrogate +if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) +{ +// expect next \uxxxx entry +if (JSON_LIKELY(get() == '\\' and get() == 'u')) +{ +const int codepoint2 = get_codepoint(); + +if (JSON_UNLIKELY(codepoint2 == -1)) +{ +error_message = "invalid string: '\\u' must be followed by 4 hex digits"; +return token_type::parse_error; +} + +// check if codepoint2 is a low surrogate +if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) +{ +// overwrite codepoint +codepoint = +// high surrogate occupies the most significant 22 bits +(codepoint1 << 10) +// low surrogate occupies the least significant 15 bits ++ codepoint2 +// there is still the 0xD800, 0xDC00 and 0x10000 noise +// in the result so we have to subtract with: +// (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 +- 0x35FDC00; +} +else +{ +error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; +return token_type::parse_error; +} +} +else +{ +error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; +return token_type::parse_error; +} +} +else +{ +if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) +{ +error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; +return token_type::parse_error; +} +} + +// result of the above calculation yields a proper codepoint +assert(0x00 <= codepoint and codepoint <= 0x10FFFF); + +// translate codepoint into bytes +if (codepoint < 0x80) +{ +// 1-byte characters: 0xxxxxxx (ASCII) +add(codepoint); +} +else if (codepoint <= 0x7FF) +{ +// 2-byte characters: 110xxxxx 10xxxxxx +add(0xC0 | (codepoint >> 6)); +add(0x80 | (codepoint & 0x3F)); +} +else if (codepoint <= 0xFFFF) +{ +// 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx +add(0xE0 | (codepoint >> 12)); +add(0x80 | ((codepoint >> 6) & 0x3F)); +add(0x80 | (codepoint & 0x3F)); +} +else +{ +// 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx +add(0xF0 | (codepoint >> 18)); +add(0x80 | ((codepoint >> 12) & 0x3F)); +add(0x80 | ((codepoint >> 6) & 0x3F)); +add(0x80 | (codepoint & 0x3F)); +} + +break; +} + +// other characters after escape +default: +error_message = "invalid string: forbidden character after backslash"; +return token_type::parse_error; +} + +break; +} + +// invalid control characters +case 0x00: +case 0x01: +case 0x02: +case 0x03: +case 0x04: +case 0x05: +case 0x06: +case 0x07: +case 0x08: +case 0x09: +case 0x0A: +case 0x0B: +case 0x0C: +case 0x0D: +case 0x0E: +case 0x0F: +case 0x10: +case 0x11: +case 0x12: +case 0x13: +case 0x14: +case 0x15: +case 0x16: +case 0x17: +case 0x18: +case 0x19: +case 0x1A: +case 0x1B: +case 0x1C: +case 0x1D: +case 0x1E: +case 0x1F: +{ +error_message = "invalid string: control character must be escaped"; +return token_type::parse_error; +} + +// U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) +case 0x20: +case 0x21: +case 0x23: +case 0x24: +case 0x25: +case 0x26: +case 0x27: +case 0x28: +case 0x29: +case 0x2A: +case 0x2B: +case 0x2C: +case 0x2D: +case 0x2E: +case 0x2F: +case 0x30: +case 0x31: +case 0x32: +case 0x33: +case 0x34: +case 0x35: +case 0x36: +case 0x37: +case 0x38: +case 0x39: +case 0x3A: +case 0x3B: +case 0x3C: +case 0x3D: +case 0x3E: +case 0x3F: +case 0x40: +case 0x41: +case 0x42: +case 0x43: +case 0x44: +case 0x45: +case 0x46: +case 0x47: +case 0x48: +case 0x49: +case 0x4A: +case 0x4B: +case 0x4C: +case 0x4D: +case 0x4E: +case 0x4F: +case 0x50: +case 0x51: +case 0x52: +case 0x53: +case 0x54: +case 0x55: +case 0x56: +case 0x57: +case 0x58: +case 0x59: +case 0x5A: +case 0x5B: +case 0x5D: +case 0x5E: +case 0x5F: +case 0x60: +case 0x61: +case 0x62: +case 0x63: +case 0x64: +case 0x65: +case 0x66: +case 0x67: +case 0x68: +case 0x69: +case 0x6A: +case 0x6B: +case 0x6C: +case 0x6D: +case 0x6E: +case 0x6F: +case 0x70: +case 0x71: +case 0x72: +case 0x73: +case 0x74: +case 0x75: +case 0x76: +case 0x77: +case 0x78: +case 0x79: +case 0x7A: +case 0x7B: +case 0x7C: +case 0x7D: +case 0x7E: +case 0x7F: +{ +add(current); +break; +} + +// U+0080..U+07FF: bytes C2..DF 80..BF +case 0xC2: +case 0xC3: +case 0xC4: +case 0xC5: +case 0xC6: +case 0xC7: +case 0xC8: +case 0xC9: +case 0xCA: +case 0xCB: +case 0xCC: +case 0xCD: +case 0xCE: +case 0xCF: +case 0xD0: +case 0xD1: +case 0xD2: +case 0xD3: +case 0xD4: +case 0xD5: +case 0xD6: +case 0xD7: +case 0xD8: +case 0xD9: +case 0xDA: +case 0xDB: +case 0xDC: +case 0xDD: +case 0xDE: +case 0xDF: +{ +if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) +{ +return token_type::parse_error; +} +break; +} + +// U+0800..U+0FFF: bytes E0 A0..BF 80..BF +case 0xE0: +{ +if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) +{ +return token_type::parse_error; +} +break; +} + +// U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF +// U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF +case 0xE1: +case 0xE2: +case 0xE3: +case 0xE4: +case 0xE5: +case 0xE6: +case 0xE7: +case 0xE8: +case 0xE9: +case 0xEA: +case 0xEB: +case 0xEC: +case 0xEE: +case 0xEF: +{ +if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) +{ +return token_type::parse_error; +} +break; +} + +// U+D000..U+D7FF: bytes ED 80..9F 80..BF +case 0xED: +{ +if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) +{ +return token_type::parse_error; +} +break; +} + +// U+10000..U+3FFFF F0 90..BF 80..BF 80..BF +case 0xF0: +{ +if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) +{ +return token_type::parse_error; +} +break; +} + +// U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF +case 0xF1: +case 0xF2: +case 0xF3: +{ +if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) +{ +return token_type::parse_error; +} +break; +} + +// U+100000..U+10FFFF F4 80..8F 80..BF 80..BF +case 0xF4: +{ +if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) +{ +return token_type::parse_error; +} +break; +} + +// remaining bytes (80..C1 and F5..FF) are ill-formed +default: +{ +error_message = "invalid string: ill-formed UTF-8 byte"; +return token_type::parse_error; +} +} +} +} + +static void strtof(float& f, const char* str, char** endptr) noexcept +{ +f = std::strtof(str, endptr); +} + +static void strtof(double& f, const char* str, char** endptr) noexcept +{ +f = std::strtod(str, endptr); +} + +static void strtof(long double& f, const char* str, char** endptr) noexcept +{ +f = std::strtold(str, endptr); +} + +/*! + @brief scan a number literal + + This function scans a string according to Sect. 6 of RFC 7159. + + The function is realized with a deterministic finite state machine derived + from the grammar described in RFC 7159. Starting in state "init", the + input is read and used to determined the next state. Only state "done" + accepts the number. State "error" is a trap state to model errors. In the + table below, "anything" means any character but the ones listed before. + + state | 0 | 1-9 | e E | + | - | . | anything + ---------|----------|----------|----------|---------|---------|----------|----------- + init | zero | any1 | [error] | [error] | minus | [error] | [error] + minus | zero | any1 | [error] | [error] | [error] | [error] | [error] + zero | done | done | exponent | done | done | decimal1 | done + any1 | any1 | any1 | exponent | done | done | decimal1 | done + decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] + decimal2 | decimal2 | decimal2 | exponent | done | done | done | done + exponent | any2 | any2 | [error] | sign | sign | [error] | [error] + sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] + any2 | any2 | any2 | done | done | done | done | done + + The state machine is realized with one label per state (prefixed with + "scan_number_") and `goto` statements between them. The state machine + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + + During scanning, the read bytes are stored in token_buffer. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + + @return token_type::value_unsigned, token_type::value_integer, or + token_type::value_float if number could be successfully scanned, + token_type::parse_error otherwise + + @note The scanner is independent of the current locale. Internally, the + locale's decimal point is used instead of `.` to work with the + locale-dependent converters. + */ +token_type scan_number() +{ +// reset token_buffer to store the number's bytes +reset(); + +// the type of the parsed number; initially set to unsigned; will be +// changed if minus sign, decimal point or exponent is read +token_type number_type = token_type::value_unsigned; + +// state (init): we just found out we need to scan a number +switch (current) +{ +case '-': +{ +add(current); +goto scan_number_minus; +} + +case '0': +{ +add(current); +goto scan_number_zero; +} + +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +{ +add(current); +goto scan_number_any1; +} + +default: +{ +// all other characters are rejected outside scan_number() +assert(false); // LCOV_EXCL_LINE +} +} + +scan_number_minus: +// state: we just parsed a leading minus sign +number_type = token_type::value_integer; +switch (get()) +{ +case '0': +{ +add(current); +goto scan_number_zero; +} + +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +{ +add(current); +goto scan_number_any1; +} + +default: +{ +error_message = "invalid number; expected digit after '-'"; +return token_type::parse_error; +} +} + +scan_number_zero: +// state: we just parse a zero (maybe with a leading minus sign) +switch (get()) +{ +case '.': +{ +add(decimal_point_char); +goto scan_number_decimal1; +} + +case 'e': +case 'E': +{ +add(current); +goto scan_number_exponent; +} + +default: +goto scan_number_done; +} + +scan_number_any1: +// state: we just parsed a number 0-9 (maybe with a leading minus sign) +switch (get()) +{ +case '0': +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +{ +add(current); +goto scan_number_any1; +} + +case '.': +{ +add(decimal_point_char); +goto scan_number_decimal1; +} + +case 'e': +case 'E': +{ +add(current); +goto scan_number_exponent; +} + +default: +goto scan_number_done; +} + +scan_number_decimal1: +// state: we just parsed a decimal point +number_type = token_type::value_float; +switch (get()) +{ +case '0': +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +{ +add(current); +goto scan_number_decimal2; +} + +default: +{ +error_message = "invalid number; expected digit after '.'"; +return token_type::parse_error; +} +} + +scan_number_decimal2: +// we just parsed at least one number after a decimal point +switch (get()) +{ +case '0': +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +{ +add(current); +goto scan_number_decimal2; +} + +case 'e': +case 'E': +{ +add(current); +goto scan_number_exponent; +} + +default: +goto scan_number_done; +} + +scan_number_exponent: +// we just parsed an exponent +number_type = token_type::value_float; +switch (get()) +{ +case '+': +case '-': +{ +add(current); +goto scan_number_sign; +} + +case '0': +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +{ +add(current); +goto scan_number_any2; +} + +default: +{ +error_message = +"invalid number; expected '+', '-', or digit after exponent"; +return token_type::parse_error; +} +} + +scan_number_sign: +// we just parsed an exponent sign +switch (get()) +{ +case '0': +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +{ +add(current); +goto scan_number_any2; +} + +default: +{ +error_message = "invalid number; expected digit after exponent sign"; +return token_type::parse_error; +} +} + +scan_number_any2: +// we just parsed a number after the exponent or exponent sign +switch (get()) +{ +case '0': +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +{ +add(current); +goto scan_number_any2; +} + +default: +goto scan_number_done; +} + +scan_number_done: +// unget the character after the number (we only read it to know that +// we are done scanning a number) +unget(); + +char* endptr = nullptr; +errno = 0; + +// try to parse integers first and fall back to floats +if (number_type == token_type::value_unsigned) +{ +const auto x = std::strtoull(token_buffer.data(), &endptr, 10); + +// we checked the number format before +assert(endptr == token_buffer.data() + token_buffer.size()); + +if (errno == 0) +{ +value_unsigned = static_cast(x); +if (value_unsigned == x) +{ +return token_type::value_unsigned; +} +} +} +else if (number_type == token_type::value_integer) +{ +const auto x = std::strtoll(token_buffer.data(), &endptr, 10); + +// we checked the number format before +assert(endptr == token_buffer.data() + token_buffer.size()); + +if (errno == 0) +{ +value_integer = static_cast(x); +if (value_integer == x) +{ +return token_type::value_integer; +} +} +} + +// this code is reached if we parse a floating-point number or if an +// integer conversion above failed +strtof(value_float, token_buffer.data(), &endptr); + +// we checked the number format before +assert(endptr == token_buffer.data() + token_buffer.size()); + +return token_type::value_float; +} + +/*! + @param[in] literal_text the literal text to expect + @param[in] length the length of the passed literal text + @param[in] return_type the token type to return on success + */ +token_type scan_literal(const char* literal_text, const std::size_t length, +token_type return_type) +{ +assert(current == literal_text[0]); +for (std::size_t i = 1; i < length; ++i) +{ +if (JSON_UNLIKELY(get() != literal_text[i])) +{ +error_message = "invalid literal"; +return token_type::parse_error; +} +} +return return_type; +} + +///////////////////// +// input management +///////////////////// + +/// reset token_buffer; current character is beginning of token +void reset() noexcept +{ +token_buffer.clear(); +token_string.clear(); +token_string.push_back(std::char_traits::to_char_type(current)); +} + +/* + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a + `std::char_traits::eof()` in that case. Stores the scanned characters + for use in error messages. + + @return character read from the input + */ +std::char_traits::int_type get() +{ +++chars_read; +current = ia->get_character(); +if (JSON_LIKELY(current != std::char_traits::eof())) +{ +token_string.push_back(std::char_traits::to_char_type(current)); +} +return current; +} + +/// unget current character (return it again on next get) +void unget() +{ +--chars_read; +if (JSON_LIKELY(current != std::char_traits::eof())) +{ +ia->unget_character(); +assert(token_string.size() != 0); +token_string.pop_back(); +} +} + +/// add a character to token_buffer +void add(int c) +{ +token_buffer.push_back(std::char_traits::to_char_type(c)); +} + +public: +///////////////////// +// value getters +///////////////////// + +/// return integer value +constexpr number_integer_t get_number_integer() const noexcept +{ +return value_integer; +} + +/// return unsigned integer value +constexpr number_unsigned_t get_number_unsigned() const noexcept +{ +return value_unsigned; +} + +/// return floating-point value +constexpr number_float_t get_number_float() const noexcept +{ +return value_float; +} + +/// return current string value (implicitly resets the token; useful only once) +std::string move_string() +{ +return std::move(token_buffer); +} + +///////////////////// +// diagnostics +///////////////////// + +/// return position of last read token +constexpr std::size_t get_position() const noexcept +{ +return chars_read; +} + +/// return the last read token (for errors only). Will never contain EOF +/// (an arbitrary value that is not a valid char value, often -1), because +/// 255 may legitimately occur. May contain NUL, which should be escaped. +std::string get_token_string() const +{ +// escape control characters +std::string result; +for (const auto c : token_string) +{ +if ('\x00' <= c and c <= '\x1F') +{ +// escape control characters +std::stringstream ss; +ss << "(c) << ">"; +result += ss.str(); +} +else +{ +// add character as is +result.push_back(c); +} +} + +return result; +} + +/// return syntax error message +constexpr const char* get_error_message() const noexcept +{ +return error_message; +} + +///////////////////// +// actual scanner +///////////////////// + +token_type scan() +{ +// read next character and ignore whitespace +do +{ +get(); +} +while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); + +switch (current) +{ +// structural characters +case '[': +return token_type::begin_array; +case ']': +return token_type::end_array; +case '{': +return token_type::begin_object; +case '}': +return token_type::end_object; +case ':': +return token_type::name_separator; +case ',': +return token_type::value_separator; + +// literals +case 't': +return scan_literal("true", 4, token_type::literal_true); +case 'f': +return scan_literal("false", 5, token_type::literal_false); +case 'n': +return scan_literal("null", 4, token_type::literal_null); + +// string +case '\"': +return scan_string(); + +// number +case '-': +case '0': +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +return scan_number(); + +// end of input (the null byte is needed when parsing from +// string literals) +case '\0': +case std::char_traits::eof(): +return token_type::end_of_input; + +// error +default: +error_message = "invalid literal"; +return token_type::parse_error; +} +} + +private: +/// input adapter +detail::input_adapter_t ia = nullptr; + +/// the current character +std::char_traits::int_type current = std::char_traits::eof(); + +/// the number of characters read +std::size_t chars_read = 0; + +/// raw input token string (for error messages) +std::vector token_string {}; + +/// buffer for variable-length tokens (numbers, strings) +std::string token_buffer {}; + +/// a description of occurred lexer errors +const char* error_message = ""; + +// number values +number_integer_t value_integer = 0; +number_unsigned_t value_unsigned = 0; +number_float_t value_float = 0; + +/// the decimal point +const char decimal_point_char = '.'; +}; +} +} + +// #include + + +#include // assert +#include // isfinite +#include // uint8_t +#include // function +#include // string +#include // move + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +//////////// +// parser // +//////////// + +/*! +@brief syntax analysis + +This class implements a recursive decent parser. +*/ +template +class parser +{ +using number_integer_t = typename BasicJsonType::number_integer_t; +using number_unsigned_t = typename BasicJsonType::number_unsigned_t; +using number_float_t = typename BasicJsonType::number_float_t; +using lexer_t = lexer; +using token_type = typename lexer_t::token_type; + +public: +enum class parse_event_t : uint8_t +{ +/// the parser read `{` and started to process a JSON object +object_start, +/// the parser read `}` and finished processing a JSON object +object_end, +/// the parser read `[` and started to process a JSON array +array_start, +/// the parser read `]` and finished processing a JSON array +array_end, +/// the parser read a key of a value in an object +key, +/// the parser finished reading a JSON value +value +}; + +using parser_callback_t = +std::function; + +/// a parser reading from an input adapter +explicit parser(detail::input_adapter_t adapter, +const parser_callback_t cb = nullptr, +const bool allow_exceptions_ = true) +: callback(cb), m_lexer(adapter), allow_exceptions(allow_exceptions_) +{} + +/*! + @brief public parser interface + + @param[in] strict whether to expect the last token to be EOF + @param[in,out] result parsed JSON value + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ +void parse(const bool strict, BasicJsonType& result) +{ +// read first token +get_token(); + +parse_internal(true, result); +result.assert_invariant(); + +// in strict mode, input must be completely read +if (strict) +{ +get_token(); +expect(token_type::end_of_input); +} + +// in case of an error, return discarded value +if (errored) +{ +result = value_t::discarded; +return; +} + +// set top-level value to null if it was discarded by the callback +// function +if (result.is_discarded()) +{ +result = nullptr; +} +} + +/*! + @brief public accept interface + + @param[in] strict whether to expect the last token to be EOF + @return whether the input is a proper JSON text + */ +bool accept(const bool strict = true) +{ +// read first token +get_token(); + +if (not accept_internal()) +{ +return false; +} + +// strict => last token must be EOF +return not strict or (get_token() == token_type::end_of_input); +} + +private: +/*! + @brief the actual parser + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ +void parse_internal(bool keep, BasicJsonType& result) +{ +// never parse after a parse error was detected +assert(not errored); + +// start with a discarded value +if (not result.is_discarded()) +{ +result.m_value.destroy(result.m_type); +result.m_type = value_t::discarded; +} + +switch (last_token) +{ +case token_type::begin_object: +{ +if (keep) +{ +if (callback) +{ +keep = callback(depth++, parse_event_t::object_start, result); +} + +if (not callback or keep) +{ +// explicitly set result to object to cope with {} +result.m_type = value_t::object; +result.m_value = value_t::object; +} +} + +// read next token +get_token(); + +// closing } -> we are done +if (last_token == token_type::end_object) +{ +if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) +{ +result.m_value.destroy(result.m_type); +result.m_type = value_t::discarded; +} +break; +} + +// parse values +std::string key; +BasicJsonType value; +while (true) +{ +// store key +if (not expect(token_type::value_string)) +{ +return; +} +key = m_lexer.move_string(); + +bool keep_tag = false; +if (keep) +{ +if (callback) +{ +BasicJsonType k(key); +keep_tag = callback(depth, parse_event_t::key, k); +} +else +{ +keep_tag = true; +} +} + +// parse separator (:) +get_token(); +if (not expect(token_type::name_separator)) +{ +return; +} + +// parse and add value +get_token(); +value.m_value.destroy(value.m_type); +value.m_type = value_t::discarded; +parse_internal(keep, value); + +if (JSON_UNLIKELY(errored)) +{ +return; +} + +if (keep and keep_tag and not value.is_discarded()) +{ +result.m_value.object->emplace(std::move(key), std::move(value)); +} + +// comma -> next value +get_token(); +if (last_token == token_type::value_separator) +{ +get_token(); +continue; +} + +// closing } +if (not expect(token_type::end_object)) +{ +return; +} +break; +} + +if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) +{ +result.m_value.destroy(result.m_type); +result.m_type = value_t::discarded; +} +break; +} + +case token_type::begin_array: +{ +if (keep) +{ +if (callback) +{ +keep = callback(depth++, parse_event_t::array_start, result); +} + +if (not callback or keep) +{ +// explicitly set result to array to cope with [] +result.m_type = value_t::array; +result.m_value = value_t::array; +} +} + +// read next token +get_token(); + +// closing ] -> we are done +if (last_token == token_type::end_array) +{ +if (callback and not callback(--depth, parse_event_t::array_end, result)) +{ +result.m_value.destroy(result.m_type); +result.m_type = value_t::discarded; +} +break; +} + +// parse values +BasicJsonType value; +while (true) +{ +// parse value +value.m_value.destroy(value.m_type); +value.m_type = value_t::discarded; +parse_internal(keep, value); + +if (JSON_UNLIKELY(errored)) +{ +return; +} + +if (keep and not value.is_discarded()) +{ +result.m_value.array->push_back(std::move(value)); +} + +// comma -> next value +get_token(); +if (last_token == token_type::value_separator) +{ +get_token(); +continue; +} + +// closing ] +if (not expect(token_type::end_array)) +{ +return; +} +break; +} + +if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) +{ +result.m_value.destroy(result.m_type); +result.m_type = value_t::discarded; +} +break; +} + +case token_type::literal_null: +{ +result.m_type = value_t::null; +break; +} + +case token_type::value_string: +{ +result.m_type = value_t::string; +result.m_value = m_lexer.move_string(); +break; +} + +case token_type::literal_true: +{ +result.m_type = value_t::boolean; +result.m_value = true; +break; +} + +case token_type::literal_false: +{ +result.m_type = value_t::boolean; +result.m_value = false; +break; +} + +case token_type::value_unsigned: +{ +result.m_type = value_t::number_unsigned; +result.m_value = m_lexer.get_number_unsigned(); +break; +} + +case token_type::value_integer: +{ +result.m_type = value_t::number_integer; +result.m_value = m_lexer.get_number_integer(); +break; +} + +case token_type::value_float: +{ +result.m_type = value_t::number_float; +result.m_value = m_lexer.get_number_float(); + +// throw in case of infinity or NAN +if (JSON_UNLIKELY(not std::isfinite(result.m_value.number_float))) +{ +if (allow_exceptions) +{ +JSON_THROW(out_of_range::create(406, "number overflow parsing '" + +m_lexer.get_token_string() + "'")); +} +expect(token_type::uninitialized); +} +break; +} + +case token_type::parse_error: +{ +// using "uninitialized" to avoid "expected" message +if (not expect(token_type::uninitialized)) +{ +return; +} +break; // LCOV_EXCL_LINE +} + +default: +{ +// the last token was unexpected; we expected a value +if (not expect(token_type::literal_or_value)) +{ +return; +} +break; // LCOV_EXCL_LINE +} +} + +if (keep and callback and not callback(depth, parse_event_t::value, result)) +{ +result.m_type = value_t::discarded; +} +} + +/*! + @brief the actual acceptor + + @invariant 1. The last token is not yet processed. Therefore, the caller + of this function must make sure a token has been read. + 2. When this function returns, the last token is processed. + That is, the last read character was already considered. + + This invariant makes sure that no token needs to be "unput". + */ +bool accept_internal() +{ +switch (last_token) +{ +case token_type::begin_object: +{ +// read next token +get_token(); + +// closing } -> we are done +if (last_token == token_type::end_object) +{ +return true; +} + +// parse values +while (true) +{ +// parse key +if (last_token != token_type::value_string) +{ +return false; +} + +// parse separator (:) +get_token(); +if (last_token != token_type::name_separator) +{ +return false; +} + +// parse value +get_token(); +if (not accept_internal()) +{ +return false; +} + +// comma -> next value +get_token(); +if (last_token == token_type::value_separator) +{ +get_token(); +continue; +} + +// closing } +return (last_token == token_type::end_object); +} +} + +case token_type::begin_array: +{ +// read next token +get_token(); + +// closing ] -> we are done +if (last_token == token_type::end_array) +{ +return true; +} + +// parse values +while (true) +{ +// parse value +if (not accept_internal()) +{ +return false; +} + +// comma -> next value +get_token(); +if (last_token == token_type::value_separator) +{ +get_token(); +continue; +} + +// closing ] +return (last_token == token_type::end_array); +} +} + +case token_type::value_float: +{ +// reject infinity or NAN +return std::isfinite(m_lexer.get_number_float()); +} + +case token_type::literal_false: +case token_type::literal_null: +case token_type::literal_true: +case token_type::value_integer: +case token_type::value_string: +case token_type::value_unsigned: +return true; + +default: // the last token was unexpected +return false; +} +} + +/// get next token from lexer +token_type get_token() +{ +return (last_token = m_lexer.scan()); +} + +/*! + @throw parse_error.101 if expected token did not occur + */ +bool expect(token_type t) +{ +if (JSON_UNLIKELY(t != last_token)) +{ +errored = true; +expected = t; +if (allow_exceptions) +{ +throw_exception(); +} +else +{ +return false; +} +} + +return true; +} + +[[noreturn]] void throw_exception() const +{ +std::string error_msg = "syntax error - "; +if (last_token == token_type::parse_error) +{ +error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + +m_lexer.get_token_string() + "'"; +} +else +{ +error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token)); +} + +if (expected != token_type::uninitialized) +{ +error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); +} + +JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); +} + +private: +/// current level of recursion +int depth = 0; +/// callback function +const parser_callback_t callback = nullptr; +/// the type of the last read token +token_type last_token = token_type::uninitialized; +/// the lexer +lexer_t m_lexer; +/// whether a syntax error occurred +bool errored = false; +/// possible reason for the syntax error +token_type expected = token_type::uninitialized; +/// whether to throw exceptions in case of errors +const bool allow_exceptions = true; +}; +} +} + +// #include + + +#include // ptrdiff_t +#include // numeric_limits + +namespace nlohmann +{ +namespace detail +{ +/* +@brief an iterator for primitive JSON types + +This class models an iterator for primitive JSON types (boolean, number, +string). It's only purpose is to allow the iterator/const_iterator classes +to "iterate" over primitive values. Internally, the iterator is modeled by +a `difference_type` variable. Value begin_value (`0`) models the begin, +end_value (`1`) models past the end. +*/ +class primitive_iterator_t +{ +private: +using difference_type = std::ptrdiff_t; +static constexpr difference_type begin_value = 0; +static constexpr difference_type end_value = begin_value + 1; + +/// iterator as signed integer type +difference_type m_it = (std::numeric_limits::min)(); + +public: +constexpr difference_type get_value() const noexcept +{ +return m_it; +} + +/// set iterator to a defined beginning +void set_begin() noexcept +{ +m_it = begin_value; +} + +/// set iterator to a defined past the end +void set_end() noexcept +{ +m_it = end_value; +} + +/// return whether the iterator can be dereferenced +constexpr bool is_begin() const noexcept +{ +return m_it == begin_value; +} + +/// return whether the iterator is at end +constexpr bool is_end() const noexcept +{ +return m_it == end_value; +} + +friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept +{ +return lhs.m_it == rhs.m_it; +} + +friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept +{ +return lhs.m_it < rhs.m_it; +} + +primitive_iterator_t operator+(difference_type n) noexcept +{ +auto result = *this; +result += n; +return result; +} + +friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept +{ +return lhs.m_it - rhs.m_it; +} + +primitive_iterator_t& operator++() noexcept +{ +++m_it; +return *this; +} + +primitive_iterator_t const operator++(int) noexcept +{ +auto result = *this; +m_it++; +return result; +} + +primitive_iterator_t& operator--() noexcept +{ +--m_it; +return *this; +} + +primitive_iterator_t const operator--(int) noexcept +{ +auto result = *this; +m_it--; +return result; +} + +primitive_iterator_t& operator+=(difference_type n) noexcept +{ +m_it += n; +return *this; +} + +primitive_iterator_t& operator-=(difference_type n) noexcept +{ +m_it -= n; +return *this; +} +}; +} +} + +// #include + + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/*! +@brief an iterator value + +@note This structure could easily be a union, but MSVC currently does not allow +unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. +*/ +template struct internal_iterator +{ +/// iterator for JSON objects +typename BasicJsonType::object_t::iterator object_iterator {}; +/// iterator for JSON arrays +typename BasicJsonType::array_t::iterator array_iterator {}; +/// generic iterator for all other types +primitive_iterator_t primitive_iterator {}; +}; +} +} + +// #include + + +#include // not +#include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next +#include // conditional, is_const, remove_const + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +// forward declare, to be able to friend it later on +template class iteration_proxy; + +/*! +@brief a template for a bidirectional iterator for the @ref basic_json class + +This class implements a both iterators (iterator and const_iterator) for the +@ref basic_json class. + +@note An iterator is called *initialized* when a pointer to a JSON value has + been set (e.g., by a constructor or a copy assignment). If the iterator is + default-constructed, it is *uninitialized* and most methods are undefined. + **The library uses assertions to detect calls on uninitialized iterators.** + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). + +@since version 1.0.0, simplified in version 2.0.9, change to bidirectional + iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) +*/ +template +class iter_impl +{ +/// allow basic_json to access private members +friend iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; +friend BasicJsonType; +friend iteration_proxy; + +using object_t = typename BasicJsonType::object_t; +using array_t = typename BasicJsonType::array_t; +// make sure BasicJsonType is basic_json or const basic_json +static_assert(is_basic_json::type>::value, +"iter_impl only accepts (const) basic_json"); + +public: + +/// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. +/// The C++ Standard has never required user-defined iterators to derive from std::iterator. +/// A user-defined iterator should provide publicly accessible typedefs named +/// iterator_category, value_type, difference_type, pointer, and reference. +/// Note that value_type is required to be non-const, even for constant iterators. +using iterator_category = std::bidirectional_iterator_tag; + +/// the type of the values when the iterator is dereferenced +using value_type = typename BasicJsonType::value_type; +/// a type to represent differences between iterators +using difference_type = typename BasicJsonType::difference_type; +/// defines a pointer to the type iterated over (value_type) +using pointer = typename std::conditional::value, +typename BasicJsonType::const_pointer, +typename BasicJsonType::pointer>::type; +/// defines a reference to the type iterated over (value_type) +using reference = +typename std::conditional::value, +typename BasicJsonType::const_reference, +typename BasicJsonType::reference>::type; + +/// default constructor +iter_impl() = default; + +/*! + @brief constructor for a given JSON instance + @param[in] object pointer to a JSON object for this iterator + @pre object != nullptr + @post The iterator is initialized; i.e. `m_object != nullptr`. + */ +explicit iter_impl(pointer object) noexcept : m_object(object) +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +{ +m_it.object_iterator = typename object_t::iterator(); +break; +} + +case value_t::array: +{ +m_it.array_iterator = typename array_t::iterator(); +break; +} + +default: +{ +m_it.primitive_iterator = primitive_iterator_t(); +break; +} +} +} + +/*! + @note The conventional copy constructor and copy assignment are implicitly + defined. Combined with the following converting constructor and + assignment, they support: (1) copy from iterator to iterator, (2) + copy from const iterator to const iterator, and (3) conversion from + iterator to const iterator. However conversion from const iterator + to iterator is not defined. + */ + +/*! + @brief converting constructor + @param[in] other non-const iterator to copy from + @note It is not checked whether @a other is initialized. + */ +iter_impl(const iter_impl::type>& other) noexcept +: m_object(other.m_object), m_it(other.m_it) {} + +/*! + @brief converting assignment + @param[in,out] other non-const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ +iter_impl& operator=(const iter_impl::type>& other) noexcept +{ +m_object = other.m_object; +m_it = other.m_it; +return *this; +} + +private: +/*! + @brief set the iterator to the first value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +void set_begin() noexcept +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +{ +m_it.object_iterator = m_object->m_value.object->begin(); +break; +} + +case value_t::array: +{ +m_it.array_iterator = m_object->m_value.array->begin(); +break; +} + +case value_t::null: +{ +// set to end so begin()==end() is true: null is empty +m_it.primitive_iterator.set_end(); +break; +} + +default: +{ +m_it.primitive_iterator.set_begin(); +break; +} +} +} + +/*! + @brief set the iterator past the last value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +void set_end() noexcept +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +{ +m_it.object_iterator = m_object->m_value.object->end(); +break; +} + +case value_t::array: +{ +m_it.array_iterator = m_object->m_value.array->end(); +break; +} + +default: +{ +m_it.primitive_iterator.set_end(); +break; +} +} +} + +public: +/*! + @brief return a reference to the value pointed to by the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +reference operator*() const +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +{ +assert(m_it.object_iterator != m_object->m_value.object->end()); +return m_it.object_iterator->second; +} + +case value_t::array: +{ +assert(m_it.array_iterator != m_object->m_value.array->end()); +return *m_it.array_iterator; +} + +case value_t::null: +JSON_THROW(invalid_iterator::create(214, "cannot get value")); + +default: +{ +if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) +{ +return *m_object; +} + +JSON_THROW(invalid_iterator::create(214, "cannot get value")); +} +} +} + +/*! + @brief dereference the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +pointer operator->() const +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +{ +assert(m_it.object_iterator != m_object->m_value.object->end()); +return &(m_it.object_iterator->second); +} + +case value_t::array: +{ +assert(m_it.array_iterator != m_object->m_value.array->end()); +return &*m_it.array_iterator; +} + +default: +{ +if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) +{ +return m_object; +} + +JSON_THROW(invalid_iterator::create(214, "cannot get value")); +} +} +} + +/*! + @brief post-increment (it++) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +iter_impl const operator++(int) +{ +auto result = *this; +++(*this); +return result; +} + +/*! + @brief pre-increment (++it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +iter_impl& operator++() +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +{ +std::advance(m_it.object_iterator, 1); +break; +} + +case value_t::array: +{ +std::advance(m_it.array_iterator, 1); +break; +} + +default: +{ +++m_it.primitive_iterator; +break; +} +} + +return *this; +} + +/*! + @brief post-decrement (it--) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +iter_impl const operator--(int) +{ +auto result = *this; +--(*this); +return result; +} + +/*! + @brief pre-decrement (--it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +iter_impl& operator--() +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +{ +std::advance(m_it.object_iterator, -1); +break; +} + +case value_t::array: +{ +std::advance(m_it.array_iterator, -1); +break; +} + +default: +{ +--m_it.primitive_iterator; +break; +} +} + +return *this; +} + +/*! + @brief comparison: equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +bool operator==(const iter_impl& other) const +{ +// if objects are not the same, the comparison is undefined +if (JSON_UNLIKELY(m_object != other.m_object)) +{ +JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); +} + +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +return (m_it.object_iterator == other.m_it.object_iterator); + +case value_t::array: +return (m_it.array_iterator == other.m_it.array_iterator); + +default: +return (m_it.primitive_iterator == other.m_it.primitive_iterator); +} +} + +/*! + @brief comparison: not equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +bool operator!=(const iter_impl& other) const +{ +return not operator==(other); +} + +/*! + @brief comparison: smaller + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +bool operator<(const iter_impl& other) const +{ +// if objects are not the same, the comparison is undefined +if (JSON_UNLIKELY(m_object != other.m_object)) +{ +JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); +} + +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators")); + +case value_t::array: +return (m_it.array_iterator < other.m_it.array_iterator); + +default: +return (m_it.primitive_iterator < other.m_it.primitive_iterator); +} +} + +/*! + @brief comparison: less than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +bool operator<=(const iter_impl& other) const +{ +return not other.operator < (*this); +} + +/*! + @brief comparison: greater than + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +bool operator>(const iter_impl& other) const +{ +return not operator<=(other); +} + +/*! + @brief comparison: greater than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +bool operator>=(const iter_impl& other) const +{ +return not operator<(other); +} + +/*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +iter_impl& operator+=(difference_type i) +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + +case value_t::array: +{ +std::advance(m_it.array_iterator, i); +break; +} + +default: +{ +m_it.primitive_iterator += i; +break; +} +} + +return *this; +} + +/*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +iter_impl& operator-=(difference_type i) +{ +return operator+=(-i); +} + +/*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +iter_impl operator+(difference_type i) const +{ +auto result = *this; +result += i; +return result; +} + +/*! + @brief addition of distance and iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +friend iter_impl operator+(difference_type i, const iter_impl& it) +{ +auto result = it; +result += i; +return result; +} + +/*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +iter_impl operator-(difference_type i) const +{ +auto result = *this; +result -= i; +return result; +} + +/*! + @brief return difference + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +difference_type operator-(const iter_impl& other) const +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + +case value_t::array: +return m_it.array_iterator - other.m_it.array_iterator; + +default: +return m_it.primitive_iterator - other.m_it.primitive_iterator; +} +} + +/*! + @brief access to successor + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +reference operator[](difference_type n) const +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators")); + +case value_t::array: +return *std::next(m_it.array_iterator, n); + +case value_t::null: +JSON_THROW(invalid_iterator::create(214, "cannot get value")); + +default: +{ +if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n)) +{ +return *m_object; +} + +JSON_THROW(invalid_iterator::create(214, "cannot get value")); +} +} +} + +/*! + @brief return the key of an object iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +typename object_t::key_type key() const +{ +assert(m_object != nullptr); + +if (JSON_LIKELY(m_object->is_object())) +{ +return m_it.object_iterator->first; +} + +JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators")); +} + +/*! + @brief return the value of an iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +reference value() const +{ +return operator*(); +} + +private: +/// associated JSON instance +pointer m_object = nullptr; +/// the actual iterator of the associated instance +internal_iterator::type> m_it; +}; +} +} + +// #include + + +#include // size_t +#include // string, to_string + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/// proxy class for the items() function +template class iteration_proxy +{ +private: +/// helper class for iteration +class iteration_proxy_internal +{ +private: +/// the iterator +IteratorType anchor; +/// an index for arrays (used to create key names) +std::size_t array_index = 0; + +public: +explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} + +/// dereference operator (needed for range-based for) +iteration_proxy_internal& operator*() +{ +return *this; +} + +/// increment operator (needed for range-based for) +iteration_proxy_internal& operator++() +{ +++anchor; +++array_index; + +return *this; +} + +/// inequality operator (needed for range-based for) +bool operator!=(const iteration_proxy_internal& o) const noexcept +{ +return anchor != o.anchor; +} + +/// return key of the iterator +std::string key() const +{ +assert(anchor.m_object != nullptr); + +switch (anchor.m_object->type()) +{ +// use integer array index as key +case value_t::array: +return std::to_string(array_index); + +// use key from the object +case value_t::object: +return anchor.key(); + +// use an empty key for all primitive types +default: +return ""; +} +} + +/// return value of the iterator +typename IteratorType::reference value() const +{ +return anchor.value(); +} +}; + +/// the container to iterate +typename IteratorType::reference container; + +public: +/// construct iteration proxy from a container +explicit iteration_proxy(typename IteratorType::reference cont) noexcept +: container(cont) {} + +/// return iterator begin (needed for range-based for) +iteration_proxy_internal begin() noexcept +{ +return iteration_proxy_internal(container.begin()); +} + +/// return iterator end (needed for range-based for) +iteration_proxy_internal end() noexcept +{ +return iteration_proxy_internal(container.end()); +} +}; +} +} + +// #include + + +#include // ptrdiff_t +#include // reverse_iterator +#include // declval + +namespace nlohmann +{ +namespace detail +{ +////////////////////// +// reverse_iterator // +////////////////////// + +/*! +@brief a template for a reverse iterator class + +@tparam Base the base iterator type to reverse. Valid types are @ref +iterator (to create @ref reverse_iterator) and @ref const_iterator (to +create @ref const_reverse_iterator). + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +- [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + +@since version 1.0.0 +*/ +template +class json_reverse_iterator : public std::reverse_iterator +{ +public: +using difference_type = std::ptrdiff_t; +/// shortcut to the reverse iterator adapter +using base_iterator = std::reverse_iterator; +/// the reference type for the pointed-to element +using reference = typename Base::reference; + +/// create reverse iterator from iterator +json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept +: base_iterator(it) {} + +/// create reverse iterator from base class +json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} + +/// post-increment (it++) +json_reverse_iterator const operator++(int) +{ +return static_cast(base_iterator::operator++(1)); +} + +/// pre-increment (++it) +json_reverse_iterator& operator++() +{ +return static_cast(base_iterator::operator++()); +} + +/// post-decrement (it--) +json_reverse_iterator const operator--(int) +{ +return static_cast(base_iterator::operator--(1)); +} + +/// pre-decrement (--it) +json_reverse_iterator& operator--() +{ +return static_cast(base_iterator::operator--()); +} + +/// add to iterator +json_reverse_iterator& operator+=(difference_type i) +{ +return static_cast(base_iterator::operator+=(i)); +} + +/// add to iterator +json_reverse_iterator operator+(difference_type i) const +{ +return static_cast(base_iterator::operator+(i)); +} + +/// subtract from iterator +json_reverse_iterator operator-(difference_type i) const +{ +return static_cast(base_iterator::operator-(i)); +} + +/// return difference +difference_type operator-(const json_reverse_iterator& other) const +{ +return base_iterator(*this) - base_iterator(other); +} + +/// access to successor +reference operator[](difference_type n) const +{ +return *(this->operator+(n)); +} + +/// return the key of an object iterator +auto key() const -> decltype(std::declval().key()) +{ +auto it = --this->base(); +return it.key(); +} + +/// return the value of an iterator +reference value() const +{ +auto it = --this->base(); +return it.operator * (); +} +}; +} +} + +// #include + + +#include // copy +#include // size_t +#include // streamsize +#include // back_inserter +#include // shared_ptr, make_shared +#include // basic_ostream +#include // basic_string +#include // vector + +namespace nlohmann +{ +namespace detail +{ +/// abstract output adapter interface +template struct output_adapter_protocol +{ +virtual void write_character(CharType c) = 0; +virtual void write_characters(const CharType* s, std::size_t length) = 0; +virtual ~output_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +template +using output_adapter_t = std::shared_ptr>; + +/// output adapter for byte vectors +template +class output_vector_adapter : public output_adapter_protocol +{ +public: +explicit output_vector_adapter(std::vector& vec) : v(vec) {} + +void write_character(CharType c) override +{ +v.push_back(c); +} + +void write_characters(const CharType* s, std::size_t length) override +{ +std::copy(s, s + length, std::back_inserter(v)); +} + +private: +std::vector& v; +}; + +/// output adapter for output streams +template +class output_stream_adapter : public output_adapter_protocol +{ +public: +explicit output_stream_adapter(std::basic_ostream& s) : stream(s) {} + +void write_character(CharType c) override +{ +stream.put(c); +} + +void write_characters(const CharType* s, std::size_t length) override +{ +stream.write(s, static_cast(length)); +} + +private: +std::basic_ostream& stream; +}; + +/// output adapter for basic_string +template +class output_string_adapter : public output_adapter_protocol +{ +public: +explicit output_string_adapter(std::basic_string& s) : str(s) {} + +void write_character(CharType c) override +{ +str.push_back(c); +} + +void write_characters(const CharType* s, std::size_t length) override +{ +str.append(s, length); +} + +private: +std::basic_string& str; +}; + +template +class output_adapter +{ +public: +output_adapter(std::vector& vec) +: oa(std::make_shared>(vec)) {} + +output_adapter(std::basic_ostream& s) +: oa(std::make_shared>(s)) {} + +output_adapter(std::basic_string& s) +: oa(std::make_shared>(s)) {} + +operator output_adapter_t() +{ +return oa; +} + +private: +output_adapter_t oa = nullptr; +}; +} +} + +// #include + + +#include // generate_n +#include // array +#include // assert +#include // ldexp +#include // size_t +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // setw, setfill +#include // hex +#include // back_inserter +#include // numeric_limits +#include // stringstream +#include // char_traits, string +#include // make_pair, move + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary reader // +/////////////////// + +/*! +@brief deserialization of CBOR and MessagePack values +*/ +template +class binary_reader +{ +using number_integer_t = typename BasicJsonType::number_integer_t; +using number_unsigned_t = typename BasicJsonType::number_unsigned_t; +using string_t = typename BasicJsonType::string_t; + +public: +/*! + @brief create a binary reader + + @param[in] adapter input adapter to read from + */ +explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter)) +{ +assert(ia); +} + +/*! + @brief create a JSON value from CBOR input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from CBOR input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ +BasicJsonType parse_cbor(const bool strict) +{ +const auto res = parse_cbor_internal(); +if (strict) +{ +get(); +expect_eof(); +} +return res; +} + +/*! + @brief create a JSON value from MessagePack input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from MessagePack input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ +BasicJsonType parse_msgpack(const bool strict) +{ +const auto res = parse_msgpack_internal(); +if (strict) +{ +get(); +expect_eof(); +} +return res; +} + +/*! + @brief create a JSON value from UBJSON input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from UBJSON input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ +BasicJsonType parse_ubjson(const bool strict) +{ +const auto res = parse_ubjson_internal(); +if (strict) +{ +get_ignore_noop(); +expect_eof(); +} +return res; +} + +/*! + @brief determine system byte order + + @return true if and only if system's byte order is little endian + + @note from http://stackoverflow.com/a/1001328/266378 + */ +static constexpr bool little_endianess(int num = 1) noexcept +{ +return (*reinterpret_cast(&num) == 1); +} + +private: +/*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + */ +BasicJsonType parse_cbor_internal(const bool get_char = true) +{ +switch (get_char ? get() : current) +{ +// EOF +case std::char_traits::eof(): +JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + +// Integer 0x00..0x17 (0..23) +case 0x00: +case 0x01: +case 0x02: +case 0x03: +case 0x04: +case 0x05: +case 0x06: +case 0x07: +case 0x08: +case 0x09: +case 0x0A: +case 0x0B: +case 0x0C: +case 0x0D: +case 0x0E: +case 0x0F: +case 0x10: +case 0x11: +case 0x12: +case 0x13: +case 0x14: +case 0x15: +case 0x16: +case 0x17: +return static_cast(current); + +case 0x18: // Unsigned integer (one-byte uint8_t follows) +return get_number(); + +case 0x19: // Unsigned integer (two-byte uint16_t follows) +return get_number(); + +case 0x1A: // Unsigned integer (four-byte uint32_t follows) +return get_number(); + +case 0x1B: // Unsigned integer (eight-byte uint64_t follows) +return get_number(); + +// Negative integer -1-0x00..-1-0x17 (-1..-24) +case 0x20: +case 0x21: +case 0x22: +case 0x23: +case 0x24: +case 0x25: +case 0x26: +case 0x27: +case 0x28: +case 0x29: +case 0x2A: +case 0x2B: +case 0x2C: +case 0x2D: +case 0x2E: +case 0x2F: +case 0x30: +case 0x31: +case 0x32: +case 0x33: +case 0x34: +case 0x35: +case 0x36: +case 0x37: +return static_cast(0x20 - 1 - current); + +case 0x38: // Negative integer (one-byte uint8_t follows) +{ +return static_cast(-1) - get_number(); +} + +case 0x39: // Negative integer -1-n (two-byte uint16_t follows) +{ +return static_cast(-1) - get_number(); +} + +case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) +{ +return static_cast(-1) - get_number(); +} + +case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) +{ +return static_cast(-1) - +static_cast(get_number()); +} + +// UTF-8 string (0x00..0x17 bytes follow) +case 0x60: +case 0x61: +case 0x62: +case 0x63: +case 0x64: +case 0x65: +case 0x66: +case 0x67: +case 0x68: +case 0x69: +case 0x6A: +case 0x6B: +case 0x6C: +case 0x6D: +case 0x6E: +case 0x6F: +case 0x70: +case 0x71: +case 0x72: +case 0x73: +case 0x74: +case 0x75: +case 0x76: +case 0x77: +case 0x78: // UTF-8 string (one-byte uint8_t for n follows) +case 0x79: // UTF-8 string (two-byte uint16_t for n follow) +case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) +case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) +case 0x7F: // UTF-8 string (indefinite length) +{ +return get_cbor_string(); +} + +// array (0x00..0x17 data items follow) +case 0x80: +case 0x81: +case 0x82: +case 0x83: +case 0x84: +case 0x85: +case 0x86: +case 0x87: +case 0x88: +case 0x89: +case 0x8A: +case 0x8B: +case 0x8C: +case 0x8D: +case 0x8E: +case 0x8F: +case 0x90: +case 0x91: +case 0x92: +case 0x93: +case 0x94: +case 0x95: +case 0x96: +case 0x97: +{ +return get_cbor_array(current & 0x1F); +} + +case 0x98: // array (one-byte uint8_t for n follows) +{ +return get_cbor_array(get_number()); +} + +case 0x99: // array (two-byte uint16_t for n follow) +{ +return get_cbor_array(get_number()); +} + +case 0x9A: // array (four-byte uint32_t for n follow) +{ +return get_cbor_array(get_number()); +} + +case 0x9B: // array (eight-byte uint64_t for n follow) +{ +return get_cbor_array(get_number()); +} + +case 0x9F: // array (indefinite length) +{ +BasicJsonType result = value_t::array; +while (get() != 0xFF) +{ +result.push_back(parse_cbor_internal(false)); +} +return result; +} + +// map (0x00..0x17 pairs of data items follow) +case 0xA0: +case 0xA1: +case 0xA2: +case 0xA3: +case 0xA4: +case 0xA5: +case 0xA6: +case 0xA7: +case 0xA8: +case 0xA9: +case 0xAA: +case 0xAB: +case 0xAC: +case 0xAD: +case 0xAE: +case 0xAF: +case 0xB0: +case 0xB1: +case 0xB2: +case 0xB3: +case 0xB4: +case 0xB5: +case 0xB6: +case 0xB7: +{ +return get_cbor_object(current & 0x1F); +} + +case 0xB8: // map (one-byte uint8_t for n follows) +{ +return get_cbor_object(get_number()); +} + +case 0xB9: // map (two-byte uint16_t for n follow) +{ +return get_cbor_object(get_number()); +} + +case 0xBA: // map (four-byte uint32_t for n follow) +{ +return get_cbor_object(get_number()); +} + +case 0xBB: // map (eight-byte uint64_t for n follow) +{ +return get_cbor_object(get_number()); +} + +case 0xBF: // map (indefinite length) +{ +BasicJsonType result = value_t::object; +while (get() != 0xFF) +{ +auto key = get_cbor_string(); +result[key] = parse_cbor_internal(); +} +return result; +} + +case 0xF4: // false +{ +return false; +} + +case 0xF5: // true +{ +return true; +} + +case 0xF6: // null +{ +return value_t::null; +} + +case 0xF9: // Half-Precision Float (two-byte IEEE 754) +{ +const int byte1 = get(); +unexpect_eof(); +const int byte2 = get(); +unexpect_eof(); + +// code from RFC 7049, Appendix D, Figure 3: +// As half-precision floating-point numbers were only added +// to IEEE 754 in 2008, today's programming platforms often +// still only have limited support for them. It is very +// easy to include at least decoding support for them even +// without such support. An example of a small decoder for +// half-precision floating-point numbers in the C language +// is shown in Fig. 3. +const int half = (byte1 << 8) + byte2; +const int exp = (half >> 10) & 0x1F; +const int mant = half & 0x3FF; +double val; +if (exp == 0) +{ +val = std::ldexp(mant, -24); +} +else if (exp != 31) +{ +val = std::ldexp(mant + 1024, exp - 25); +} +else +{ +val = (mant == 0) ? std::numeric_limits::infinity() +: std::numeric_limits::quiet_NaN(); +} +return (half & 0x8000) != 0 ? -val : val; +} + +case 0xFA: // Single-Precision Float (four-byte IEEE 754) +{ +return get_number(); +} + +case 0xFB: // Double-Precision Float (eight-byte IEEE 754) +{ +return get_number(); +} + +default: // anything else (0xFF is handled inside the other types) +{ +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; +JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str())); +} +} +} + +BasicJsonType parse_msgpack_internal() +{ +switch (get()) +{ +// EOF +case std::char_traits::eof(): +JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + +// positive fixint +case 0x00: +case 0x01: +case 0x02: +case 0x03: +case 0x04: +case 0x05: +case 0x06: +case 0x07: +case 0x08: +case 0x09: +case 0x0A: +case 0x0B: +case 0x0C: +case 0x0D: +case 0x0E: +case 0x0F: +case 0x10: +case 0x11: +case 0x12: +case 0x13: +case 0x14: +case 0x15: +case 0x16: +case 0x17: +case 0x18: +case 0x19: +case 0x1A: +case 0x1B: +case 0x1C: +case 0x1D: +case 0x1E: +case 0x1F: +case 0x20: +case 0x21: +case 0x22: +case 0x23: +case 0x24: +case 0x25: +case 0x26: +case 0x27: +case 0x28: +case 0x29: +case 0x2A: +case 0x2B: +case 0x2C: +case 0x2D: +case 0x2E: +case 0x2F: +case 0x30: +case 0x31: +case 0x32: +case 0x33: +case 0x34: +case 0x35: +case 0x36: +case 0x37: +case 0x38: +case 0x39: +case 0x3A: +case 0x3B: +case 0x3C: +case 0x3D: +case 0x3E: +case 0x3F: +case 0x40: +case 0x41: +case 0x42: +case 0x43: +case 0x44: +case 0x45: +case 0x46: +case 0x47: +case 0x48: +case 0x49: +case 0x4A: +case 0x4B: +case 0x4C: +case 0x4D: +case 0x4E: +case 0x4F: +case 0x50: +case 0x51: +case 0x52: +case 0x53: +case 0x54: +case 0x55: +case 0x56: +case 0x57: +case 0x58: +case 0x59: +case 0x5A: +case 0x5B: +case 0x5C: +case 0x5D: +case 0x5E: +case 0x5F: +case 0x60: +case 0x61: +case 0x62: +case 0x63: +case 0x64: +case 0x65: +case 0x66: +case 0x67: +case 0x68: +case 0x69: +case 0x6A: +case 0x6B: +case 0x6C: +case 0x6D: +case 0x6E: +case 0x6F: +case 0x70: +case 0x71: +case 0x72: +case 0x73: +case 0x74: +case 0x75: +case 0x76: +case 0x77: +case 0x78: +case 0x79: +case 0x7A: +case 0x7B: +case 0x7C: +case 0x7D: +case 0x7E: +case 0x7F: +return static_cast(current); + +// fixmap +case 0x80: +case 0x81: +case 0x82: +case 0x83: +case 0x84: +case 0x85: +case 0x86: +case 0x87: +case 0x88: +case 0x89: +case 0x8A: +case 0x8B: +case 0x8C: +case 0x8D: +case 0x8E: +case 0x8F: +{ +return get_msgpack_object(current & 0x0F); +} + +// fixarray +case 0x90: +case 0x91: +case 0x92: +case 0x93: +case 0x94: +case 0x95: +case 0x96: +case 0x97: +case 0x98: +case 0x99: +case 0x9A: +case 0x9B: +case 0x9C: +case 0x9D: +case 0x9E: +case 0x9F: +{ +return get_msgpack_array(current & 0x0F); +} + +// fixstr +case 0xA0: +case 0xA1: +case 0xA2: +case 0xA3: +case 0xA4: +case 0xA5: +case 0xA6: +case 0xA7: +case 0xA8: +case 0xA9: +case 0xAA: +case 0xAB: +case 0xAC: +case 0xAD: +case 0xAE: +case 0xAF: +case 0xB0: +case 0xB1: +case 0xB2: +case 0xB3: +case 0xB4: +case 0xB5: +case 0xB6: +case 0xB7: +case 0xB8: +case 0xB9: +case 0xBA: +case 0xBB: +case 0xBC: +case 0xBD: +case 0xBE: +case 0xBF: +return get_msgpack_string(); + +case 0xC0: // nil +return value_t::null; + +case 0xC2: // false +return false; + +case 0xC3: // true +return true; + +case 0xCA: // float 32 +return get_number(); + +case 0xCB: // float 64 +return get_number(); + +case 0xCC: // uint 8 +return get_number(); + +case 0xCD: // uint 16 +return get_number(); + +case 0xCE: // uint 32 +return get_number(); + +case 0xCF: // uint 64 +return get_number(); + +case 0xD0: // int 8 +return get_number(); + +case 0xD1: // int 16 +return get_number(); + +case 0xD2: // int 32 +return get_number(); + +case 0xD3: // int 64 +return get_number(); + +case 0xD9: // str 8 +case 0xDA: // str 16 +case 0xDB: // str 32 +return get_msgpack_string(); + +case 0xDC: // array 16 +{ +return get_msgpack_array(get_number()); +} + +case 0xDD: // array 32 +{ +return get_msgpack_array(get_number()); +} + +case 0xDE: // map 16 +{ +return get_msgpack_object(get_number()); +} + +case 0xDF: // map 32 +{ +return get_msgpack_object(get_number()); +} + +// positive fixint +case 0xE0: +case 0xE1: +case 0xE2: +case 0xE3: +case 0xE4: +case 0xE5: +case 0xE6: +case 0xE7: +case 0xE8: +case 0xE9: +case 0xEA: +case 0xEB: +case 0xEC: +case 0xED: +case 0xEE: +case 0xEF: +case 0xF0: +case 0xF1: +case 0xF2: +case 0xF3: +case 0xF4: +case 0xF5: +case 0xF6: +case 0xF7: +case 0xF8: +case 0xF9: +case 0xFA: +case 0xFB: +case 0xFC: +case 0xFD: +case 0xFE: +case 0xFF: +return static_cast(current); + +default: // anything else +{ +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; +JSON_THROW(parse_error::create(112, chars_read, +"error reading MessagePack; last byte: 0x" + ss.str())); +} +} +} + +/*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + */ +BasicJsonType parse_ubjson_internal(const bool get_char = true) +{ +return get_ubjson_value(get_char ? get_ignore_noop() : current); +} + +/*! + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a -'ve valued + `std::char_traits::eof()` in that case. + + @return character read from the input + */ +int get() +{ +++chars_read; +return (current = ia->get_character()); +} + +/*! + @return character read from the input after ignoring all 'N' entries + */ +int get_ignore_noop() +{ +do +{ +get(); +} +while (current == 'N'); + +return current; +} + +/* + @brief read a number from the input + + @tparam NumberType the type of the number + + @return number of type @a NumberType + + @note This function needs to respect the system's endianess, because + bytes in CBOR and MessagePack are stored in network order (big + endian) and therefore need reordering on little endian systems. + + @throw parse_error.110 if input has less than `sizeof(NumberType)` bytes + */ +template NumberType get_number() +{ +// step 1: read input into array with system's byte order +std::array vec; +for (std::size_t i = 0; i < sizeof(NumberType); ++i) +{ +get(); +unexpect_eof(); + +// reverse byte order prior to conversion if necessary +if (is_little_endian) +{ +vec[sizeof(NumberType) - i - 1] = static_cast(current); +} +else +{ +vec[i] = static_cast(current); // LCOV_EXCL_LINE +} +} + +// step 2: convert array into number of type T and return +NumberType result; +std::memcpy(&result, vec.data(), sizeof(NumberType)); +return result; +} + +/*! + @brief create a string by reading characters from the input + + @param[in] len number of bytes to read + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref unexpect_eof() detects the end of + the input before we run out of string memory. + + @return string created by reading @a len bytes + + @throw parse_error.110 if input has less than @a len bytes + */ +template +string_t get_string(const NumberType len) +{ +string_t result; +std::generate_n(std::back_inserter(result), len, [this]() +{ +get(); +unexpect_eof(); +return static_cast(current); +}); +return result; +} + +/*! + @brief reads a CBOR string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + Additionally, CBOR's strings with indefinite lengths are supported. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ +string_t get_cbor_string() +{ +unexpect_eof(); + +switch (current) +{ +// UTF-8 string (0x00..0x17 bytes follow) +case 0x60: +case 0x61: +case 0x62: +case 0x63: +case 0x64: +case 0x65: +case 0x66: +case 0x67: +case 0x68: +case 0x69: +case 0x6A: +case 0x6B: +case 0x6C: +case 0x6D: +case 0x6E: +case 0x6F: +case 0x70: +case 0x71: +case 0x72: +case 0x73: +case 0x74: +case 0x75: +case 0x76: +case 0x77: +{ +return get_string(current & 0x1F); +} + +case 0x78: // UTF-8 string (one-byte uint8_t for n follows) +{ +return get_string(get_number()); +} + +case 0x79: // UTF-8 string (two-byte uint16_t for n follow) +{ +return get_string(get_number()); +} + +case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) +{ +return get_string(get_number()); +} + +case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) +{ +return get_string(get_number()); +} + +case 0x7F: // UTF-8 string (indefinite length) +{ +string_t result; +while (get() != 0xFF) +{ +unexpect_eof(); +result.push_back(static_cast(current)); +} +return result; +} + +default: +{ +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; +JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str())); +} +} +} + +template +BasicJsonType get_cbor_array(const NumberType len) +{ +BasicJsonType result = value_t::array; +std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() +{ +return parse_cbor_internal(); +}); +return result; +} + +template +BasicJsonType get_cbor_object(const NumberType len) +{ +BasicJsonType result = value_t::object; +std::generate_n(std::inserter(*result.m_value.object, +result.m_value.object->end()), +len, [this]() +{ +get(); +auto key = get_cbor_string(); +auto val = parse_cbor_internal(); +return std::make_pair(std::move(key), std::move(val)); +}); +return result; +} + +/*! + @brief reads a MessagePack string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ +string_t get_msgpack_string() +{ +unexpect_eof(); + +switch (current) +{ +// fixstr +case 0xA0: +case 0xA1: +case 0xA2: +case 0xA3: +case 0xA4: +case 0xA5: +case 0xA6: +case 0xA7: +case 0xA8: +case 0xA9: +case 0xAA: +case 0xAB: +case 0xAC: +case 0xAD: +case 0xAE: +case 0xAF: +case 0xB0: +case 0xB1: +case 0xB2: +case 0xB3: +case 0xB4: +case 0xB5: +case 0xB6: +case 0xB7: +case 0xB8: +case 0xB9: +case 0xBA: +case 0xBB: +case 0xBC: +case 0xBD: +case 0xBE: +case 0xBF: +{ +return get_string(current & 0x1F); +} + +case 0xD9: // str 8 +{ +return get_string(get_number()); +} + +case 0xDA: // str 16 +{ +return get_string(get_number()); +} + +case 0xDB: // str 32 +{ +return get_string(get_number()); +} + +default: +{ +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; +JSON_THROW(parse_error::create(113, chars_read, +"expected a MessagePack string; last byte: 0x" + ss.str())); +} +} +} + +template +BasicJsonType get_msgpack_array(const NumberType len) +{ +BasicJsonType result = value_t::array; +std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() +{ +return parse_msgpack_internal(); +}); +return result; +} + +template +BasicJsonType get_msgpack_object(const NumberType len) +{ +BasicJsonType result = value_t::object; +std::generate_n(std::inserter(*result.m_value.object, +result.m_value.object->end()), +len, [this]() +{ +get(); +auto key = get_msgpack_string(); +auto val = parse_msgpack_internal(); +return std::make_pair(std::move(key), std::move(val)); +}); +return result; +} + +/*! + @brief reads a UBJSON string + + This function is either called after reading the 'S' byte explicitly + indicating a string, or in case of an object key where the 'S' byte can be + left out. + + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ +string_t get_ubjson_string(const bool get_char = true) +{ +if (get_char) +{ +get(); // TODO: may we ignore N here? +} + +unexpect_eof(); + +switch (current) +{ +case 'U': +return get_string(get_number()); +case 'i': +return get_string(get_number()); +case 'I': +return get_string(get_number()); +case 'l': +return get_string(get_number()); +case 'L': +return get_string(get_number()); +default: +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; +JSON_THROW(parse_error::create(113, chars_read, +"expected a UBJSON string; last byte: 0x" + ss.str())); +} +} + +/*! + @brief determine the type and size for a container + + In the optimized UBJSON format, a type and a size can be provided to allow + for a more compact representation. + + @return pair of the size and the type + */ +std::pair get_ubjson_size_type() +{ +std::size_t sz = string_t::npos; +int tc = 0; + +get_ignore_noop(); + +if (current == '$') +{ +tc = get(); // must not ignore 'N', because 'N' maybe the type +unexpect_eof(); + +get_ignore_noop(); +if (current != '#') +{ +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; +JSON_THROW(parse_error::create(112, chars_read, +"expected '#' after UBJSON type information; last byte: 0x" + ss.str())); +} +sz = parse_ubjson_internal(); +} +else if (current == '#') +{ +sz = parse_ubjson_internal(); +} + +return std::make_pair(sz, tc); +} + +BasicJsonType get_ubjson_value(const int prefix) +{ +switch (prefix) +{ +case std::char_traits::eof(): // EOF +JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + +case 'T': // true +return true; +case 'F': // false +return false; + +case 'Z': // null +return nullptr; + +case 'U': +return get_number(); +case 'i': +return get_number(); +case 'I': +return get_number(); +case 'l': +return get_number(); +case 'L': +return get_number(); +case 'd': +return get_number(); +case 'D': +return get_number(); + +case 'C': // char +{ +get(); +unexpect_eof(); +if (JSON_UNLIKELY(current > 127)) +{ +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; +JSON_THROW(parse_error::create(113, chars_read, +"byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + ss.str())); +} +return string_t(1, static_cast(current)); +} + +case 'S': // string +return get_ubjson_string(); + +case '[': // array +return get_ubjson_array(); + +case '{': // object +return get_ubjson_object(); + +default: // anything else +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; +JSON_THROW(parse_error::create(112, chars_read, +"error reading UBJSON; last byte: 0x" + ss.str())); +} +} + +BasicJsonType get_ubjson_array() +{ +BasicJsonType result = value_t::array; +const auto size_and_type = get_ubjson_size_type(); + +if (size_and_type.first != string_t::npos) +{ +if (size_and_type.second != 0) +{ +if (size_and_type.second != 'N') +std::generate_n(std::back_inserter(*result.m_value.array), +size_and_type.first, [this, size_and_type]() +{ +return get_ubjson_value(size_and_type.second); +}); +} +else +{ +std::generate_n(std::back_inserter(*result.m_value.array), +size_and_type.first, [this]() +{ +return parse_ubjson_internal(); +}); +} +} +else +{ +while (current != ']') +{ +result.push_back(parse_ubjson_internal(false)); +get_ignore_noop(); +} +} + +return result; +} + +BasicJsonType get_ubjson_object() +{ +BasicJsonType result = value_t::object; +const auto size_and_type = get_ubjson_size_type(); + +if (size_and_type.first != string_t::npos) +{ +if (size_and_type.second != 0) +{ +std::generate_n(std::inserter(*result.m_value.object, +result.m_value.object->end()), +size_and_type.first, [this, size_and_type]() +{ +auto key = get_ubjson_string(); +auto val = get_ubjson_value(size_and_type.second); +return std::make_pair(std::move(key), std::move(val)); +}); +} +else +{ +std::generate_n(std::inserter(*result.m_value.object, +result.m_value.object->end()), +size_and_type.first, [this]() +{ +auto key = get_ubjson_string(); +auto val = parse_ubjson_internal(); +return std::make_pair(std::move(key), std::move(val)); +}); +} +} +else +{ +while (current != '}') +{ +auto key = get_ubjson_string(false); +result[std::move(key)] = parse_ubjson_internal(); +get_ignore_noop(); +} +} + +return result; +} + +/*! + @brief throw if end of input is not reached + @throw parse_error.110 if input not ended + */ +void expect_eof() const +{ +if (JSON_UNLIKELY(current != std::char_traits::eof())) +{ +JSON_THROW(parse_error::create(110, chars_read, "expected end of input")); +} +} + +/*! + @briefthrow if end of input is reached + @throw parse_error.110 if input ended + */ +void unexpect_eof() const +{ +if (JSON_UNLIKELY(current == std::char_traits::eof())) +{ +JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); +} +} + +private: +/// input adapter +input_adapter_t ia = nullptr; + +/// the current character +int current = std::char_traits::eof(); + +/// the number of characters read +std::size_t chars_read = 0; + +/// whether we can assume little endianess +const bool is_little_endian = little_endianess(); +}; +} +} + +// #include + + +#include // reverse +#include // array +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // numeric_limits + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary writer // +/////////////////// + +/*! +@brief serialization to CBOR and MessagePack values +*/ +template +class binary_writer +{ +public: +/*! + @brief create a binary writer + + @param[in] adapter output adapter to write to + */ +explicit binary_writer(output_adapter_t adapter) : oa(adapter) +{ +assert(oa); +} + +/*! + @brief[in] j JSON value to serialize + */ +void write_cbor(const BasicJsonType& j) +{ +switch (j.type()) +{ +case value_t::null: +{ +oa->write_character(static_cast(0xF6)); +break; +} + +case value_t::boolean: +{ +oa->write_character(j.m_value.boolean +? static_cast(0xF5) +: static_cast(0xF4)); +break; +} + +case value_t::number_integer: +{ +if (j.m_value.number_integer >= 0) +{ +// CBOR does not differentiate between positive signed +// integers and unsigned integers. Therefore, we used the +// code from the value_t::number_unsigned case here. +if (j.m_value.number_integer <= 0x17) +{ +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x18)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x19)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x1A)); +write_number(static_cast(j.m_value.number_integer)); +} +else +{ +oa->write_character(static_cast(0x1B)); +write_number(static_cast(j.m_value.number_integer)); +} +} +else +{ +// The conversions below encode the sign in the first +// byte, and the value is converted to a positive number. +const auto positive_number = -1 - j.m_value.number_integer; +if (j.m_value.number_integer >= -24) +{ +write_number(static_cast(0x20 + positive_number)); +} +else if (positive_number <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x38)); +write_number(static_cast(positive_number)); +} +else if (positive_number <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x39)); +write_number(static_cast(positive_number)); +} +else if (positive_number <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x3A)); +write_number(static_cast(positive_number)); +} +else +{ +oa->write_character(static_cast(0x3B)); +write_number(static_cast(positive_number)); +} +} +break; +} + +case value_t::number_unsigned: +{ +if (j.m_value.number_unsigned <= 0x17) +{ +write_number(static_cast(j.m_value.number_unsigned)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x18)); +write_number(static_cast(j.m_value.number_unsigned)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x19)); +write_number(static_cast(j.m_value.number_unsigned)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x1A)); +write_number(static_cast(j.m_value.number_unsigned)); +} +else +{ +oa->write_character(static_cast(0x1B)); +write_number(static_cast(j.m_value.number_unsigned)); +} +break; +} + +case value_t::number_float: // Double-Precision Float +{ +oa->write_character(static_cast(0xFB)); +write_number(j.m_value.number_float); +break; +} + +case value_t::string: +{ +// step 1: write control byte and the string length +const auto N = j.m_value.string->size(); +if (N <= 0x17) +{ +write_number(static_cast(0x60 + N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x78)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x79)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x7A)); +write_number(static_cast(N)); +} +// LCOV_EXCL_START +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x7B)); +write_number(static_cast(N)); +} +// LCOV_EXCL_STOP + +// step 2: write the string +oa->write_characters( +reinterpret_cast(j.m_value.string->c_str()), +j.m_value.string->size()); +break; +} + +case value_t::array: +{ +// step 1: write control byte and the array size +const auto N = j.m_value.array->size(); +if (N <= 0x17) +{ +write_number(static_cast(0x80 + N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x98)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x99)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x9A)); +write_number(static_cast(N)); +} +// LCOV_EXCL_START +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x9B)); +write_number(static_cast(N)); +} +// LCOV_EXCL_STOP + +// step 2: write each element +for (const auto& el : *j.m_value.array) +{ +write_cbor(el); +} +break; +} + +case value_t::object: +{ +// step 1: write control byte and the object size +const auto N = j.m_value.object->size(); +if (N <= 0x17) +{ +write_number(static_cast(0xA0 + N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0xB8)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0xB9)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0xBA)); +write_number(static_cast(N)); +} +// LCOV_EXCL_START +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0xBB)); +write_number(static_cast(N)); +} +// LCOV_EXCL_STOP + +// step 2: write each element +for (const auto& el : *j.m_value.object) +{ +write_cbor(el.first); +write_cbor(el.second); +} +break; +} + +default: +break; +} +} + +/*! + @brief[in] j JSON value to serialize + */ +void write_msgpack(const BasicJsonType& j) +{ +switch (j.type()) +{ +case value_t::null: // nil +{ +oa->write_character(static_cast(0xC0)); +break; +} + +case value_t::boolean: // true and false +{ +oa->write_character(j.m_value.boolean +? static_cast(0xC3) +: static_cast(0xC2)); +break; +} + +case value_t::number_integer: +{ +if (j.m_value.number_integer >= 0) +{ +// MessagePack does not differentiate between positive +// signed integers and unsigned integers. Therefore, we used +// the code from the value_t::number_unsigned case here. +if (j.m_value.number_unsigned < 128) +{ +// positive fixnum +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +// uint 8 +oa->write_character(static_cast(0xCC)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +// uint 16 +oa->write_character(static_cast(0xCD)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +// uint 32 +oa->write_character(static_cast(0xCE)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +// uint 64 +oa->write_character(static_cast(0xCF)); +write_number(static_cast(j.m_value.number_integer)); +} +} +else +{ +if (j.m_value.number_integer >= -32) +{ +// negative fixnum +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_integer >= (std::numeric_limits::min)() and +j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +// int 8 +oa->write_character(static_cast(0xD0)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_integer >= (std::numeric_limits::min)() and +j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +// int 16 +oa->write_character(static_cast(0xD1)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_integer >= (std::numeric_limits::min)() and +j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +// int 32 +oa->write_character(static_cast(0xD2)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_integer >= (std::numeric_limits::min)() and +j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +// int 64 +oa->write_character(static_cast(0xD3)); +write_number(static_cast(j.m_value.number_integer)); +} +} +break; +} + +case value_t::number_unsigned: +{ +if (j.m_value.number_unsigned < 128) +{ +// positive fixnum +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +// uint 8 +oa->write_character(static_cast(0xCC)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +// uint 16 +oa->write_character(static_cast(0xCD)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +// uint 32 +oa->write_character(static_cast(0xCE)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +// uint 64 +oa->write_character(static_cast(0xCF)); +write_number(static_cast(j.m_value.number_integer)); +} +break; +} + +case value_t::number_float: // float 64 +{ +oa->write_character(static_cast(0xCB)); +write_number(j.m_value.number_float); +break; +} + +case value_t::string: +{ +// step 1: write control byte and the string length +const auto N = j.m_value.string->size(); +if (N <= 31) +{ +// fixstr +write_number(static_cast(0xA0 | N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +// str 8 +oa->write_character(static_cast(0xD9)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +// str 16 +oa->write_character(static_cast(0xDA)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +// str 32 +oa->write_character(static_cast(0xDB)); +write_number(static_cast(N)); +} + +// step 2: write the string +oa->write_characters( +reinterpret_cast(j.m_value.string->c_str()), +j.m_value.string->size()); +break; +} + +case value_t::array: +{ +// step 1: write control byte and the array size +const auto N = j.m_value.array->size(); +if (N <= 15) +{ +// fixarray +write_number(static_cast(0x90 | N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +// array 16 +oa->write_character(static_cast(0xDC)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +// array 32 +oa->write_character(static_cast(0xDD)); +write_number(static_cast(N)); +} + +// step 2: write each element +for (const auto& el : *j.m_value.array) +{ +write_msgpack(el); +} +break; +} + +case value_t::object: +{ +// step 1: write control byte and the object size +const auto N = j.m_value.object->size(); +if (N <= 15) +{ +// fixmap +write_number(static_cast(0x80 | (N & 0xF))); +} +else if (N <= (std::numeric_limits::max)()) +{ +// map 16 +oa->write_character(static_cast(0xDE)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +// map 32 +oa->write_character(static_cast(0xDF)); +write_number(static_cast(N)); +} + +// step 2: write each element +for (const auto& el : *j.m_value.object) +{ +write_msgpack(el.first); +write_msgpack(el.second); +} +break; +} + +default: +break; +} +} + +/*! + @param[in] j JSON value to serialize + @param[in] use_count whether to use '#' prefixes (optimized format) + @param[in] use_type whether to use '$' prefixes (optimized format) + @param[in] add_prefix whether prefixes need to be used for this value + */ +void write_ubjson(const BasicJsonType& j, const bool use_count, +const bool use_type, const bool add_prefix = true) +{ +switch (j.type()) +{ +case value_t::null: +{ +if (add_prefix) +{ +oa->write_character(static_cast('Z')); +} +break; +} + +case value_t::boolean: +{ +if (add_prefix) +oa->write_character(j.m_value.boolean +? static_cast('T') +: static_cast('F')); +break; +} + +case value_t::number_integer: +{ +write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix); +break; +} + +case value_t::number_unsigned: +{ +write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix); +break; +} + +case value_t::number_float: +{ +write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix); +break; +} + +case value_t::string: +{ +if (add_prefix) +{ +oa->write_character(static_cast('S')); +} +write_number_with_ubjson_prefix(j.m_value.string->size(), true); +oa->write_characters( +reinterpret_cast(j.m_value.string->c_str()), +j.m_value.string->size()); +break; +} + +case value_t::array: +{ +if (add_prefix) +{ +oa->write_character(static_cast('[')); +} + +bool prefix_required = true; +if (use_type and not j.m_value.array->empty()) +{ +assert(use_count); +const char first_prefix = ubjson_prefix(j.front()); +const bool same_prefix = std::all_of(j.begin() + 1, j.end(), +[this, first_prefix](const BasicJsonType & v) +{ +return ubjson_prefix(v) == first_prefix; +}); + +if (same_prefix) +{ +prefix_required = false; +oa->write_character(static_cast('$')); +oa->write_character(static_cast(first_prefix)); +} +} + +if (use_count) +{ +oa->write_character(static_cast('#')); +write_number_with_ubjson_prefix(j.m_value.array->size(), true); +} + +for (const auto& el : *j.m_value.array) +{ +write_ubjson(el, use_count, use_type, prefix_required); +} + +if (not use_count) +{ +oa->write_character(static_cast(']')); +} + +break; +} + +case value_t::object: +{ +if (add_prefix) +{ +oa->write_character(static_cast('{')); +} + +bool prefix_required = true; +if (use_type and not j.m_value.object->empty()) +{ +assert(use_count); +const char first_prefix = ubjson_prefix(j.front()); +const bool same_prefix = std::all_of(j.begin(), j.end(), +[this, first_prefix](const BasicJsonType & v) +{ +return ubjson_prefix(v) == first_prefix; +}); + +if (same_prefix) +{ +prefix_required = false; +oa->write_character(static_cast('$')); +oa->write_character(static_cast(first_prefix)); +} +} + +if (use_count) +{ +oa->write_character(static_cast('#')); +write_number_with_ubjson_prefix(j.m_value.object->size(), true); +} + +for (const auto& el : *j.m_value.object) +{ +write_number_with_ubjson_prefix(el.first.size(), true); +oa->write_characters( +reinterpret_cast(el.first.c_str()), +el.first.size()); +write_ubjson(el.second, use_count, use_type, prefix_required); +} + +if (not use_count) +{ +oa->write_character(static_cast('}')); +} + +break; +} + +default: +break; +} +} + +private: +/* + @brief write a number to output input + + @param[in] n number of type @a NumberType + @tparam NumberType the type of the number + + @note This function needs to respect the system's endianess, because bytes + in CBOR, MessagePack, and UBJSON are stored in network order (big + endian) and therefore need reordering on little endian systems. + */ +template +void write_number(const NumberType n) +{ +// step 1: write number to array of length NumberType +std::array vec; +std::memcpy(vec.data(), &n, sizeof(NumberType)); + +// step 2: write array to output (with possible reordering) +if (is_little_endian) +{ +// reverse byte order prior to conversion if necessary +std::reverse(vec.begin(), vec.end()); +} + +oa->write_characters(vec.data(), sizeof(NumberType)); +} + +template +void write_number_with_ubjson_prefix(const NumberType n, +const bool add_prefix) +{ +if (std::is_floating_point::value) +{ +if (add_prefix) +{ +oa->write_character(static_cast('D')); // float64 +} +write_number(n); +} +else if (std::is_unsigned::value) +{ +if (n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('i')); // int8 +} +write_number(static_cast(n)); +} +else if (n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('U')); // uint8 +} +write_number(static_cast(n)); +} +else if (n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('I')); // int16 +} +write_number(static_cast(n)); +} +else if (n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('l')); // int32 +} +write_number(static_cast(n)); +} +else if (n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('L')); // int64 +} +write_number(static_cast(n)); +} +else +{ +JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); +} +} +else +{ +if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('i')); // int8 +} +write_number(static_cast(n)); +} +else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('U')); // uint8 +} +write_number(static_cast(n)); +} +else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('I')); // int16 +} +write_number(static_cast(n)); +} +else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('l')); // int32 +} +write_number(static_cast(n)); +} +else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('L')); // int64 +} +write_number(static_cast(n)); +} +// LCOV_EXCL_START +else +{ +JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); +} +// LCOV_EXCL_STOP +} +} + +/*! + @brief determine the type prefix of container values + + @note This function does not need to be 100% accurate when it comes to + integer limits. In case a number exceeds the limits of int64_t, + this will be detected by a later call to function + write_number_with_ubjson_prefix. Therefore, we return 'L' for any + value that does not fit the previous limits. + */ +char ubjson_prefix(const BasicJsonType& j) const noexcept +{ +switch (j.type()) +{ +case value_t::null: +return 'Z'; + +case value_t::boolean: +return j.m_value.boolean ? 'T' : 'F'; + +case value_t::number_integer: +{ +if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +return 'i'; +} +else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +return 'U'; +} +else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +return 'I'; +} +else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +return 'l'; +} +else // no check and assume int64_t (see note above) +{ +return 'L'; +} +} + +case value_t::number_unsigned: +{ +if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +return 'i'; +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +return 'U'; +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +return 'I'; +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +return 'l'; +} +else // no check and assume int64_t (see note above) +{ +return 'L'; +} +} + +case value_t::number_float: +return 'D'; + +case value_t::string: +return 'S'; + +case value_t::array: +return '['; + +case value_t::object: +return '{'; + +default: // discarded values +return 'N'; +} +} + +private: +/// whether we can assume little endianess +const bool is_little_endian = binary_reader::little_endianess(); + +/// the output +output_adapter_t oa = nullptr; +}; +} +} + +// #include + + +#include // reverse, remove, fill, find, none_of +#include // array +#include // assert +#include // and, or +#include // localeconv, lconv +#include // labs, isfinite, isnan, signbit +#include // size_t, ptrdiff_t +#include // uint8_t +#include // snprintf +#include // setfill +#include // next +#include // numeric_limits +#include // string +#include // stringstream +#include // is_same + +// #include + +// #include + + +#include // assert +#include // or, and, not +#include // signbit, isfinite +#include // intN_t, uintN_t +#include // memcpy, memmove + +namespace nlohmann +{ +namespace detail +{ + +/*! +@brief implements the Grisu2 algorithm for binary to decimal floating-point +conversion. + +This implementation is a slightly modified version of the reference +implementation which may be obtained from +http://florian.loitsch.com/publications (bench.tar.gz). + +The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch. + +For a detailed description of the algorithm see: + +[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with + Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming + Language Design and Implementation, PLDI 2010 +[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately", + Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language + Design and Implementation, PLDI 1996 +*/ +namespace dtoa_impl +{ + +template +Target reinterpret_bits(const Source source) +{ +static_assert(sizeof(Target) == sizeof(Source), "size mismatch"); + +Target target; +std::memcpy(&target, &source, sizeof(Source)); +return target; +} + +struct diyfp // f * 2^e +{ +static constexpr int kPrecision = 64; // = q + +uint64_t f; +int e; + +constexpr diyfp() noexcept : f(0), e(0) {} +constexpr diyfp(uint64_t f_, int e_) noexcept : f(f_), e(e_) {} + +/*! + @brief returns x - y + @pre x.e == y.e and x.f >= y.f + */ +static diyfp sub(const diyfp& x, const diyfp& y) noexcept +{ +assert(x.e == y.e); +assert(x.f >= y.f); + +return diyfp(x.f - y.f, x.e); +} + +/*! + @brief returns x * y + @note The result is rounded. (Only the upper q bits are returned.) + */ +static diyfp mul(const diyfp& x, const diyfp& y) noexcept +{ +static_assert(kPrecision == 64, "internal error"); + +// Computes: +// f = round((x.f * y.f) / 2^q) +// e = x.e + y.e + q + +// Emulate the 64-bit * 64-bit multiplication: +// +// p = u * v +// = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi) +// = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi ) +// = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 ) +// = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 ) +// = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3) +// = (p0_lo ) + 2^32 (Q ) + 2^64 (H ) +// = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H ) +// +// (Since Q might be larger than 2^32 - 1) +// +// = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H) +// +// (Q_hi + H does not overflow a 64-bit int) +// +// = p_lo + 2^64 p_hi + +const uint64_t u_lo = x.f & 0xFFFFFFFF; +const uint64_t u_hi = x.f >> 32; +const uint64_t v_lo = y.f & 0xFFFFFFFF; +const uint64_t v_hi = y.f >> 32; + +const uint64_t p0 = u_lo * v_lo; +const uint64_t p1 = u_lo * v_hi; +const uint64_t p2 = u_hi * v_lo; +const uint64_t p3 = u_hi * v_hi; + +const uint64_t p0_hi = p0 >> 32; +const uint64_t p1_lo = p1 & 0xFFFFFFFF; +const uint64_t p1_hi = p1 >> 32; +const uint64_t p2_lo = p2 & 0xFFFFFFFF; +const uint64_t p2_hi = p2 >> 32; + +uint64_t Q = p0_hi + p1_lo + p2_lo; + +// The full product might now be computed as +// +// p_hi = p3 + p2_hi + p1_hi + (Q >> 32) +// p_lo = p0_lo + (Q << 32) +// +// But in this particular case here, the full p_lo is not required. +// Effectively we only need to add the highest bit in p_lo to p_hi (and +// Q_hi + 1 does not overflow). + +Q += uint64_t{1} << (64 - 32 - 1); // round, ties up + +const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32); + +return diyfp(h, x.e + y.e + 64); +} + +/*! + @brief normalize x such that the significand is >= 2^(q-1) + @pre x.f != 0 + */ +static diyfp normalize(diyfp x) noexcept +{ +assert(x.f != 0); + +while ((x.f >> 63) == 0) +{ +x.f <<= 1; +x.e--; +} + +return x; +} + +/*! + @brief normalize x such that the result has the exponent E + @pre e >= x.e and the upper e - x.e bits of x.f must be zero. + */ +static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept +{ +const int delta = x.e - target_exponent; + +assert(delta >= 0); +assert(((x.f << delta) >> delta) == x.f); + +return diyfp(x.f << delta, target_exponent); +} +}; + +struct boundaries +{ +diyfp w; +diyfp minus; +diyfp plus; +}; + +/*! +Compute the (normalized) diyfp representing the input number 'value' and its +boundaries. + +@pre value must be finite and positive +*/ +template +boundaries compute_boundaries(FloatType value) +{ +assert(std::isfinite(value)); +assert(value > 0); + +// Convert the IEEE representation into a diyfp. +// +// If v is denormal: +// value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1)) +// If v is normalized: +// value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) + +static_assert(std::numeric_limits::is_iec559, +"internal error: dtoa_short requires an IEEE-754 floating-point implementation"); + +constexpr int kPrecision = std::numeric_limits::digits; // = p (includes the hidden bit) +constexpr int kBias = std::numeric_limits::max_exponent - 1 + (kPrecision - 1); +constexpr int kMinExp = 1 - kBias; +constexpr uint64_t kHiddenBit = uint64_t{1} << (kPrecision - 1); // = 2^(p-1) + +using bits_type = typename std::conditional< kPrecision == 24, uint32_t, uint64_t >::type; + +const uint64_t bits = reinterpret_bits(value); +const uint64_t E = bits >> (kPrecision - 1); +const uint64_t F = bits & (kHiddenBit - 1); + +const bool is_denormal = (E == 0); +const diyfp v = is_denormal +? diyfp(F, kMinExp) +: diyfp(F + kHiddenBit, static_cast(E) - kBias); + +// Compute the boundaries m- and m+ of the floating-point value +// v = f * 2^e. +// +// Determine v- and v+, the floating-point predecessor and successor if v, +// respectively. +// +// v- = v - 2^e if f != 2^(p-1) or e == e_min (A) +// = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B) +// +// v+ = v + 2^e +// +// Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_ +// between m- and m+ round to v, regardless of how the input rounding +// algorithm breaks ties. +// +// ---+-------------+-------------+-------------+-------------+--- (A) +// v- m- v m+ v+ +// +// -----------------+------+------+-------------+-------------+--- (B) +// v- m- v m+ v+ + +const bool lower_boundary_is_closer = (F == 0 and E > 1); +const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); +const diyfp m_minus = lower_boundary_is_closer +? diyfp(4 * v.f - 1, v.e - 2) // (B) +: diyfp(2 * v.f - 1, v.e - 1); // (A) + +// Determine the normalized w+ = m+. +const diyfp w_plus = diyfp::normalize(m_plus); + +// Determine w- = m- such that e_(w-) = e_(w+). +const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e); + +return {diyfp::normalize(v), w_minus, w_plus}; +} + +// Given normalized diyfp w, Grisu needs to find a (normalized) cached +// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies +// within a certain range [alpha, gamma] (Definition 3.2 from [1]) +// +// alpha <= e = e_c + e_w + q <= gamma +// +// or +// +// f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q +// <= f_c * f_w * 2^gamma +// +// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies +// +// 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma +// +// or +// +// 2^(q - 2 + alpha) <= c * w < 2^(q + gamma) +// +// The choice of (alpha,gamma) determines the size of the table and the form of +// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well +// in practice: +// +// The idea is to cut the number c * w = f * 2^e into two parts, which can be +// processed independently: An integral part p1, and a fractional part p2: +// +// f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e +// = (f div 2^-e) + (f mod 2^-e) * 2^e +// = p1 + p2 * 2^e +// +// The conversion of p1 into decimal form requires a series of divisions and +// modulos by (a power of) 10. These operations are faster for 32-bit than for +// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be +// achieved by choosing +// +// -e >= 32 or e <= -32 := gamma +// +// In order to convert the fractional part +// +// p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ... +// +// into decimal form, the fraction is repeatedly multiplied by 10 and the digits +// d[-i] are extracted in order: +// +// (10 * p2) div 2^-e = d[-1] +// (10 * p2) mod 2^-e = d[-2] / 10^1 + ... +// +// The multiplication by 10 must not overflow. It is sufficient to choose +// +// 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64. +// +// Since p2 = f mod 2^-e < 2^-e, +// +// -e <= 60 or e >= -60 := alpha + +constexpr int kAlpha = -60; +constexpr int kGamma = -32; + +struct cached_power // c = f * 2^e ~= 10^k +{ +uint64_t f; +int e; +int k; +}; + +/*! +For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached +power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c +satisfies (Definition 3.2 from [1]) + + alpha <= e_c + e + q <= gamma. +*/ +inline cached_power get_cached_power_for_binary_exponent(int e) +{ +// Now +// +// alpha <= e_c + e + q <= gamma (1) +// ==> f_c * 2^alpha <= c * 2^e * 2^q +// +// and since the c's are normalized, 2^(q-1) <= f_c, +// +// ==> 2^(q - 1 + alpha) <= c * 2^(e + q) +// ==> 2^(alpha - e - 1) <= c +// +// If c were an exakt power of ten, i.e. c = 10^k, one may determine k as +// +// k = ceil( log_10( 2^(alpha - e - 1) ) ) +// = ceil( (alpha - e - 1) * log_10(2) ) +// +// From the paper: +// "In theory the result of the procedure could be wrong since c is rounded, +// and the computation itself is approximated [...]. In practice, however, +// this simple function is sufficient." +// +// For IEEE double precision floating-point numbers converted into +// normalized diyfp's w = f * 2^e, with q = 64, +// +// e >= -1022 (min IEEE exponent) +// -52 (p - 1) +// -52 (p - 1, possibly normalize denormal IEEE numbers) +// -11 (normalize the diyfp) +// = -1137 +// +// and +// +// e <= +1023 (max IEEE exponent) +// -52 (p - 1) +// -11 (normalize the diyfp) +// = 960 +// +// This binary exponent range [-1137,960] results in a decimal exponent +// range [-307,324]. One does not need to store a cached power for each +// k in this range. For each such k it suffices to find a cached power +// such that the exponent of the product lies in [alpha,gamma]. +// This implies that the difference of the decimal exponents of adjacent +// table entries must be less than or equal to +// +// floor( (gamma - alpha) * log_10(2) ) = 8. +// +// (A smaller distance gamma-alpha would require a larger table.) + +// NB: +// Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. + +constexpr int kCachedPowersSize = 79; +constexpr int kCachedPowersMinDecExp = -300; +constexpr int kCachedPowersDecStep = 8; + +static constexpr cached_power kCachedPowers[] = +{ +{ 0xAB70FE17C79AC6CA, -1060, -300 }, +{ 0xFF77B1FCBEBCDC4F, -1034, -292 }, +{ 0xBE5691EF416BD60C, -1007, -284 }, +{ 0x8DD01FAD907FFC3C, -980, -276 }, +{ 0xD3515C2831559A83, -954, -268 }, +{ 0x9D71AC8FADA6C9B5, -927, -260 }, +{ 0xEA9C227723EE8BCB, -901, -252 }, +{ 0xAECC49914078536D, -874, -244 }, +{ 0x823C12795DB6CE57, -847, -236 }, +{ 0xC21094364DFB5637, -821, -228 }, +{ 0x9096EA6F3848984F, -794, -220 }, +{ 0xD77485CB25823AC7, -768, -212 }, +{ 0xA086CFCD97BF97F4, -741, -204 }, +{ 0xEF340A98172AACE5, -715, -196 }, +{ 0xB23867FB2A35B28E, -688, -188 }, +{ 0x84C8D4DFD2C63F3B, -661, -180 }, +{ 0xC5DD44271AD3CDBA, -635, -172 }, +{ 0x936B9FCEBB25C996, -608, -164 }, +{ 0xDBAC6C247D62A584, -582, -156 }, +{ 0xA3AB66580D5FDAF6, -555, -148 }, +{ 0xF3E2F893DEC3F126, -529, -140 }, +{ 0xB5B5ADA8AAFF80B8, -502, -132 }, +{ 0x87625F056C7C4A8B, -475, -124 }, +{ 0xC9BCFF6034C13053, -449, -116 }, +{ 0x964E858C91BA2655, -422, -108 }, +{ 0xDFF9772470297EBD, -396, -100 }, +{ 0xA6DFBD9FB8E5B88F, -369, -92 }, +{ 0xF8A95FCF88747D94, -343, -84 }, +{ 0xB94470938FA89BCF, -316, -76 }, +{ 0x8A08F0F8BF0F156B, -289, -68 }, +{ 0xCDB02555653131B6, -263, -60 }, +{ 0x993FE2C6D07B7FAC, -236, -52 }, +{ 0xE45C10C42A2B3B06, -210, -44 }, +{ 0xAA242499697392D3, -183, -36 }, +{ 0xFD87B5F28300CA0E, -157, -28 }, +{ 0xBCE5086492111AEB, -130, -20 }, +{ 0x8CBCCC096F5088CC, -103, -12 }, +{ 0xD1B71758E219652C, -77, -4 }, +{ 0x9C40000000000000, -50, 4 }, +{ 0xE8D4A51000000000, -24, 12 }, +{ 0xAD78EBC5AC620000, 3, 20 }, +{ 0x813F3978F8940984, 30, 28 }, +{ 0xC097CE7BC90715B3, 56, 36 }, +{ 0x8F7E32CE7BEA5C70, 83, 44 }, +{ 0xD5D238A4ABE98068, 109, 52 }, +{ 0x9F4F2726179A2245, 136, 60 }, +{ 0xED63A231D4C4FB27, 162, 68 }, +{ 0xB0DE65388CC8ADA8, 189, 76 }, +{ 0x83C7088E1AAB65DB, 216, 84 }, +{ 0xC45D1DF942711D9A, 242, 92 }, +{ 0x924D692CA61BE758, 269, 100 }, +{ 0xDA01EE641A708DEA, 295, 108 }, +{ 0xA26DA3999AEF774A, 322, 116 }, +{ 0xF209787BB47D6B85, 348, 124 }, +{ 0xB454E4A179DD1877, 375, 132 }, +{ 0x865B86925B9BC5C2, 402, 140 }, +{ 0xC83553C5C8965D3D, 428, 148 }, +{ 0x952AB45CFA97A0B3, 455, 156 }, +{ 0xDE469FBD99A05FE3, 481, 164 }, +{ 0xA59BC234DB398C25, 508, 172 }, +{ 0xF6C69A72A3989F5C, 534, 180 }, +{ 0xB7DCBF5354E9BECE, 561, 188 }, +{ 0x88FCF317F22241E2, 588, 196 }, +{ 0xCC20CE9BD35C78A5, 614, 204 }, +{ 0x98165AF37B2153DF, 641, 212 }, +{ 0xE2A0B5DC971F303A, 667, 220 }, +{ 0xA8D9D1535CE3B396, 694, 228 }, +{ 0xFB9B7CD9A4A7443C, 720, 236 }, +{ 0xBB764C4CA7A44410, 747, 244 }, +{ 0x8BAB8EEFB6409C1A, 774, 252 }, +{ 0xD01FEF10A657842C, 800, 260 }, +{ 0x9B10A4E5E9913129, 827, 268 }, +{ 0xE7109BFBA19C0C9D, 853, 276 }, +{ 0xAC2820D9623BF429, 880, 284 }, +{ 0x80444B5E7AA7CF85, 907, 292 }, +{ 0xBF21E44003ACDD2D, 933, 300 }, +{ 0x8E679C2F5E44FF8F, 960, 308 }, +{ 0xD433179D9C8CB841, 986, 316 }, +{ 0x9E19DB92B4E31BA9, 1013, 324 }, +}; + +// This computation gives exactly the same results for k as +// k = ceil((kAlpha - e - 1) * 0.30102999566398114) +// for |e| <= 1500, but doesn't require floating-point operations. +// NB: log_10(2) ~= 78913 / 2^18 +assert(e >= -1500); +assert(e <= 1500); +const int f = kAlpha - e - 1; +const int k = (f * 78913) / (1 << 18) + (f > 0); + +const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; +assert(index >= 0); +assert(index < kCachedPowersSize); +static_cast(kCachedPowersSize); // Fix warning. + +const cached_power cached = kCachedPowers[index]; +assert(kAlpha <= cached.e + e + 64); +assert(kGamma >= cached.e + e + 64); + +return cached; +} + +/*! +For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. +For n == 0, returns 1 and sets pow10 := 1. +*/ +inline int find_largest_pow10(const uint32_t n, uint32_t& pow10) +{ +// LCOV_EXCL_START +if (n >= 1000000000) +{ +pow10 = 1000000000; +return 10; +} +// LCOV_EXCL_STOP +else if (n >= 100000000) +{ +pow10 = 100000000; +return 9; +} +else if (n >= 10000000) +{ +pow10 = 10000000; +return 8; +} +else if (n >= 1000000) +{ +pow10 = 1000000; +return 7; +} +else if (n >= 100000) +{ +pow10 = 100000; +return 6; +} +else if (n >= 10000) +{ +pow10 = 10000; +return 5; +} +else if (n >= 1000) +{ +pow10 = 1000; +return 4; +} +else if (n >= 100) +{ +pow10 = 100; +return 3; +} +else if (n >= 10) +{ +pow10 = 10; +return 2; +} +else +{ +pow10 = 1; +return 1; +} +} + +inline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta, +uint64_t rest, uint64_t ten_k) +{ +assert(len >= 1); +assert(dist <= delta); +assert(rest <= delta); +assert(ten_k > 0); + +// <--------------------------- delta ----> +// <---- dist ---------> +// --------------[------------------+-------------------]-------------- +// M- w M+ +// +// ten_k +// <------> +// <---- rest ----> +// --------------[------------------+----+--------------]-------------- +// w V +// = buf * 10^k +// +// ten_k represents a unit-in-the-last-place in the decimal representation +// stored in buf. +// Decrement buf by ten_k while this takes buf closer to w. + +// The tests are written in this order to avoid overflow in unsigned +// integer arithmetic. + +while (rest < dist +and delta - rest >= ten_k +and (rest + ten_k < dist or dist - rest > rest + ten_k - dist)) +{ +assert(buf[len - 1] != '0'); +buf[len - 1]--; +rest += ten_k; +} +} + +/*! +Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+. +M- and M+ must be normalized and share the same exponent -60 <= e <= -32. +*/ +inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, +diyfp M_minus, diyfp w, diyfp M_plus) +{ +static_assert(kAlpha >= -60, "internal error"); +static_assert(kGamma <= -32, "internal error"); + +// Generates the digits (and the exponent) of a decimal floating-point +// number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's +// w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma. +// +// <--------------------------- delta ----> +// <---- dist ---------> +// --------------[------------------+-------------------]-------------- +// M- w M+ +// +// Grisu2 generates the digits of M+ from left to right and stops as soon as +// V is in [M-,M+]. + +assert(M_plus.e >= kAlpha); +assert(M_plus.e <= kGamma); + +uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) +uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) + +// Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): +// +// M+ = f * 2^e +// = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e +// = ((p1 ) * 2^-e + (p2 )) * 2^e +// = p1 + p2 * 2^e + +const diyfp one(uint64_t{1} << -M_plus.e, M_plus.e); + +uint32_t p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) +uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e + +// 1) +// +// Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] + +assert(p1 > 0); + +uint32_t pow10; +const int k = find_largest_pow10(p1, pow10); + +// 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) +// +// p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1)) +// = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1)) +// +// M+ = p1 + p2 * 2^e +// = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e +// = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e +// = d[k-1] * 10^(k-1) + ( rest) * 2^e +// +// Now generate the digits d[n] of p1 from left to right (n = k-1,...,0) +// +// p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0] +// +// but stop as soon as +// +// rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e + +int n = k; +while (n > 0) +{ +// Invariants: +// M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) +// pow10 = 10^(n-1) <= p1 < 10^n +// +const uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) +const uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) +// +// M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e +// = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) +// +assert(d <= 9); +buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d +// +// M+ = buffer * 10^(n-1) + (r + p2 * 2^e) +// +p1 = r; +n--; +// +// M+ = buffer * 10^n + (p1 + p2 * 2^e) +// pow10 = 10^n +// + +// Now check if enough digits have been generated. +// Compute +// +// p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e +// +// Note: +// Since rest and delta share the same exponent e, it suffices to +// compare the significands. +const uint64_t rest = (uint64_t{p1} << -one.e) + p2; +if (rest <= delta) +{ +// V = buffer * 10^n, with M- <= V <= M+. + +decimal_exponent += n; + +// We may now just stop. But instead look if the buffer could be +// decremented to bring V closer to w. +// +// pow10 = 10^n is now 1 ulp in the decimal representation V. +// The rounding procedure works with diyfp's with an implicit +// exponent of e. +// +// 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e +// +const uint64_t ten_n = uint64_t{pow10} << -one.e; +grisu2_round(buffer, length, dist, delta, rest, ten_n); + +return; +} + +pow10 /= 10; +// +// pow10 = 10^(n-1) <= p1 < 10^n +// Invariants restored. +} + +// 2) +// +// The digits of the integral part have been generated: +// +// M+ = d[k-1]...d[1]d[0] + p2 * 2^e +// = buffer + p2 * 2^e +// +// Now generate the digits of the fractional part p2 * 2^e. +// +// Note: +// No decimal point is generated: the exponent is adjusted instead. +// +// p2 actually represents the fraction +// +// p2 * 2^e +// = p2 / 2^-e +// = d[-1] / 10^1 + d[-2] / 10^2 + ... +// +// Now generate the digits d[-m] of p1 from left to right (m = 1,2,...) +// +// p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m +// + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...) +// +// using +// +// 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e) +// = ( d) * 2^-e + ( r) +// +// or +// 10^m * p2 * 2^e = d + r * 2^e +// +// i.e. +// +// M+ = buffer + p2 * 2^e +// = buffer + 10^-m * (d + r * 2^e) +// = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e +// +// and stop as soon as 10^-m * r * 2^e <= delta * 2^e + +assert(p2 > delta); + +int m = 0; +for (;;) +{ +// Invariant: +// M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e +// = buffer * 10^-m + 10^-m * (p2 ) * 2^e +// = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e +// = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e +// +assert(p2 <= UINT64_MAX / 10); +p2 *= 10; +const uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e +const uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e +// +// M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e +// = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) +// = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e +// +assert(d <= 9); +buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d +// +// M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e +// +p2 = r; +m++; +// +// M+ = buffer * 10^-m + 10^-m * p2 * 2^e +// Invariant restored. + +// Check if enough digits have been generated. +// +// 10^-m * p2 * 2^e <= delta * 2^e +// p2 * 2^e <= 10^m * delta * 2^e +// p2 <= 10^m * delta +delta *= 10; +dist *= 10; +if (p2 <= delta) +{ +break; +} +} + +// V = buffer * 10^-m, with M- <= V <= M+. + +decimal_exponent -= m; + +// 1 ulp in the decimal representation is now 10^-m. +// Since delta and dist are now scaled by 10^m, we need to do the +// same with ulp in order to keep the units in sync. +// +// 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e +// +const uint64_t ten_m = one.f; +grisu2_round(buffer, length, dist, delta, p2, ten_m); + +// By construction this algorithm generates the shortest possible decimal +// number (Loitsch, Theorem 6.2) which rounds back to w. +// For an input number of precision p, at least +// +// N = 1 + ceil(p * log_10(2)) +// +// decimal digits are sufficient to identify all binary floating-point +// numbers (Matula, "In-and-Out conversions"). +// This implies that the algorithm does not produce more than N decimal +// digits. +// +// N = 17 for p = 53 (IEEE double precision) +// N = 9 for p = 24 (IEEE single precision) +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +inline void grisu2(char* buf, int& len, int& decimal_exponent, +diyfp m_minus, diyfp v, diyfp m_plus) +{ +assert(m_plus.e == m_minus.e); +assert(m_plus.e == v.e); + +// --------(-----------------------+-----------------------)-------- (A) +// m- v m+ +// +// --------------------(-----------+-----------------------)-------- (B) +// m- v m+ +// +// First scale v (and m- and m+) such that the exponent is in the range +// [alpha, gamma]. + +const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e); + +const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k + +// The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma] +const diyfp w = diyfp::mul(v, c_minus_k); +const diyfp w_minus = diyfp::mul(m_minus, c_minus_k); +const diyfp w_plus = diyfp::mul(m_plus, c_minus_k); + +// ----(---+---)---------------(---+---)---------------(---+---)---- +// w- w w+ +// = c*m- = c*v = c*m+ +// +// diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and +// w+ are now off by a small amount. +// In fact: +// +// w - v * 10^k < 1 ulp +// +// To account for this inaccuracy, add resp. subtract 1 ulp. +// +// --------+---[---------------(---+---)---------------]---+-------- +// w- M- w M+ w+ +// +// Now any number in [M-, M+] (bounds included) will round to w when input, +// regardless of how the input rounding algorithm breaks ties. +// +// And digit_gen generates the shortest possible such number in [M-, M+]. +// Note that this does not mean that Grisu2 always generates the shortest +// possible number in the interval (m-, m+). +const diyfp M_minus(w_minus.f + 1, w_minus.e); +const diyfp M_plus (w_plus.f - 1, w_plus.e ); + +decimal_exponent = -cached.k; // = -(-k) = k + +grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus); +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +template +void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) +{ +static_assert(diyfp::kPrecision >= std::numeric_limits::digits + 3, +"internal error: not enough precision"); + +assert(std::isfinite(value)); +assert(value > 0); + +// If the neighbors (and boundaries) of 'value' are always computed for double-precision +// numbers, all float's can be recovered using strtod (and strtof). However, the resulting +// decimal representations are not exactly "short". +// +// The documentation for 'std::to_chars' (http://en.cppreference.com/w/cpp/utility/to_chars) +// says "value is converted to a string as if by std::sprintf in the default ("C") locale" +// and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars' +// does. +// On the other hand, the documentation for 'std::to_chars' requires that "parsing the +// representation using the corresponding std::from_chars function recovers value exactly". That +// indicates that single precision floating-point numbers should be recovered using +// 'std::strtof'. +// +// NB: If the neighbors are computed for single-precision numbers, there is a single float +// (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision +// value is off by 1 ulp. +#if 0 +const boundaries w = compute_boundaries(static_cast(value)); +#else +const boundaries w = compute_boundaries(value); +#endif + +grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus); +} + +/*! +@brief appends a decimal representation of e to buf +@return a pointer to the element following the exponent. +@pre -1000 < e < 1000 +*/ +inline char* append_exponent(char* buf, int e) +{ +assert(e > -1000); +assert(e < 1000); + +if (e < 0) +{ +e = -e; +*buf++ = '-'; +} +else +{ +*buf++ = '+'; +} + +uint32_t k = static_cast(e); +if (k < 10) +{ +// Always print at least two digits in the exponent. +// This is for compatibility with printf("%g"). +*buf++ = '0'; +*buf++ = static_cast('0' + k); +} +else if (k < 100) +{ +*buf++ = static_cast('0' + k / 10); +k %= 10; +*buf++ = static_cast('0' + k); +} +else +{ +*buf++ = static_cast('0' + k / 100); +k %= 100; +*buf++ = static_cast('0' + k / 10); +k %= 10; +*buf++ = static_cast('0' + k); +} + +return buf; +} + +/*! +@brief prettify v = buf * 10^decimal_exponent + +If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point +notation. Otherwise it will be printed in exponential notation. + +@pre min_exp < 0 +@pre max_exp > 0 +*/ +inline char* format_buffer(char* buf, int len, int decimal_exponent, +int min_exp, int max_exp) +{ +assert(min_exp < 0); +assert(max_exp > 0); + +const int k = len; +const int n = len + decimal_exponent; + +// v = buf * 10^(n-k) +// k is the length of the buffer (number of decimal digits) +// n is the position of the decimal point relative to the start of the buffer. + +if (k <= n and n <= max_exp) +{ +// digits[000] +// len <= max_exp + 2 + +std::memset(buf + k, '0', static_cast(n - k)); +// Make it look like a floating-point number (#362, #378) +buf[n + 0] = '.'; +buf[n + 1] = '0'; +return buf + (n + 2); +} + +if (0 < n and n <= max_exp) +{ +// dig.its +// len <= max_digits10 + 1 + +assert(k > n); + +std::memmove(buf + (n + 1), buf + n, static_cast(k - n)); +buf[n] = '.'; +return buf + (k + 1); +} + +if (min_exp < n and n <= 0) +{ +// 0.[000]digits +// len <= 2 + (-min_exp - 1) + max_digits10 + +std::memmove(buf + (2 + -n), buf, static_cast(k)); +buf[0] = '0'; +buf[1] = '.'; +std::memset(buf + 2, '0', static_cast(-n)); +return buf + (2 + (-n) + k); +} + +if (k == 1) +{ +// dE+123 +// len <= 1 + 5 + +buf += 1; +} +else +{ +// d.igitsE+123 +// len <= max_digits10 + 1 + 5 + +std::memmove(buf + 2, buf + 1, static_cast(k - 1)); +buf[1] = '.'; +buf += 1 + k; +} + +*buf++ = 'e'; +return append_exponent(buf, n - 1); +} + +} // namespace dtoa_impl + +/*! +@brief generates a decimal representation of the floating-point number value in [first, last). + +The format of the resulting decimal representation is similar to printf's %g +format. Returns an iterator pointing past-the-end of the decimal representation. + +@note The input number must be finite, i.e. NaN's and Inf's are not supported. +@note The buffer must be large enough. +@note The result is NOT null-terminated. +*/ +template +char* to_chars(char* first, char* last, FloatType value) +{ +static_cast(last); // maybe unused - fix warning +assert(std::isfinite(value)); + +// Use signbit(value) instead of (value < 0) since signbit works for -0. +if (std::signbit(value)) +{ +value = -value; +*first++ = '-'; +} + +if (value == 0) // +-0 +{ +*first++ = '0'; +// Make it look like a floating-point number (#362, #378) +*first++ = '.'; +*first++ = '0'; +return first; +} + +assert(last - first >= std::numeric_limits::max_digits10); + +// Compute v = buffer * 10^decimal_exponent. +// The decimal digits are stored in the buffer, which needs to be interpreted +// as an unsigned decimal integer. +// len is the length of the buffer, i.e. the number of decimal digits. +int len = 0; +int decimal_exponent = 0; +dtoa_impl::grisu2(first, len, decimal_exponent, value); + +assert(len <= std::numeric_limits::max_digits10); + +// Format the buffer like printf("%.*g", prec, value) +constexpr int kMinExp = -4; +// Use digits10 here to increase compatibility with version 2. +constexpr int kMaxExp = std::numeric_limits::digits10; + +assert(last - first >= kMaxExp + 2); +assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); +assert(last - first >= std::numeric_limits::max_digits10 + 6); + +return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); +} + +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// serialization // +/////////////////// + +template +class serializer +{ +using string_t = typename BasicJsonType::string_t; +using number_float_t = typename BasicJsonType::number_float_t; +using number_integer_t = typename BasicJsonType::number_integer_t; +using number_unsigned_t = typename BasicJsonType::number_unsigned_t; +static constexpr uint8_t UTF8_ACCEPT = 0; +static constexpr uint8_t UTF8_REJECT = 1; + +public: +/*! + @param[in] s output stream to serialize to + @param[in] ichar indentation character to use + */ +serializer(output_adapter_t s, const char ichar) +: o(std::move(s)), loc(std::localeconv()), +thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep)), +decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point)), +indent_char(ichar), indent_string(512, indent_char) +{} + +// delete because of pointer members +serializer(const serializer&) = delete; +serializer& operator=(const serializer&) = delete; + +/*! + @brief internal implementation of the serialization function + + This function is called by the public member function dump and organizes + the serialization internally. The indentation level is propagated as + additional parameter. In case of arrays and objects, the function is + called recursively. + + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format + + @param[in] val value to serialize + @param[in] pretty_print whether the output shall be pretty-printed + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) + */ +void dump(const BasicJsonType& val, const bool pretty_print, +const bool ensure_ascii, +const unsigned int indent_step, +const unsigned int current_indent = 0) +{ +switch (val.m_type) +{ +case value_t::object: +{ +if (val.m_value.object->empty()) +{ +o->write_characters("{}", 2); +return; +} + +if (pretty_print) +{ +o->write_characters("{\n", 2); + +// variable to hold indentation for recursive calls +const auto new_indent = current_indent + indent_step; +if (JSON_UNLIKELY(indent_string.size() < new_indent)) +{ +indent_string.resize(indent_string.size() * 2, ' '); +} + +// first n-1 elements +auto i = val.m_value.object->cbegin(); +for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) +{ +o->write_characters(indent_string.c_str(), new_indent); +o->write_character('\"'); +dump_escaped(i->first, ensure_ascii); +o->write_characters("\": ", 3); +dump(i->second, true, ensure_ascii, indent_step, new_indent); +o->write_characters(",\n", 2); +} + +// last element +assert(i != val.m_value.object->cend()); +assert(std::next(i) == val.m_value.object->cend()); +o->write_characters(indent_string.c_str(), new_indent); +o->write_character('\"'); +dump_escaped(i->first, ensure_ascii); +o->write_characters("\": ", 3); +dump(i->second, true, ensure_ascii, indent_step, new_indent); + +o->write_character('\n'); +o->write_characters(indent_string.c_str(), current_indent); +o->write_character('}'); +} +else +{ +o->write_character('{'); + +// first n-1 elements +auto i = val.m_value.object->cbegin(); +for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) +{ +o->write_character('\"'); +dump_escaped(i->first, ensure_ascii); +o->write_characters("\":", 2); +dump(i->second, false, ensure_ascii, indent_step, current_indent); +o->write_character(','); +} + +// last element +assert(i != val.m_value.object->cend()); +assert(std::next(i) == val.m_value.object->cend()); +o->write_character('\"'); +dump_escaped(i->first, ensure_ascii); +o->write_characters("\":", 2); +dump(i->second, false, ensure_ascii, indent_step, current_indent); + +o->write_character('}'); +} + +return; +} + +case value_t::array: +{ +if (val.m_value.array->empty()) +{ +o->write_characters("[]", 2); +return; +} + +if (pretty_print) +{ +o->write_characters("[\n", 2); + +// variable to hold indentation for recursive calls +const auto new_indent = current_indent + indent_step; +if (JSON_UNLIKELY(indent_string.size() < new_indent)) +{ +indent_string.resize(indent_string.size() * 2, ' '); +} + +// first n-1 elements +for (auto i = val.m_value.array->cbegin(); +i != val.m_value.array->cend() - 1; ++i) +{ +o->write_characters(indent_string.c_str(), new_indent); +dump(*i, true, ensure_ascii, indent_step, new_indent); +o->write_characters(",\n", 2); +} + +// last element +assert(not val.m_value.array->empty()); +o->write_characters(indent_string.c_str(), new_indent); +dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); + +o->write_character('\n'); +o->write_characters(indent_string.c_str(), current_indent); +o->write_character(']'); +} +else +{ +o->write_character('['); + +// first n-1 elements +for (auto i = val.m_value.array->cbegin(); +i != val.m_value.array->cend() - 1; ++i) +{ +dump(*i, false, ensure_ascii, indent_step, current_indent); +o->write_character(','); +} + +// last element +assert(not val.m_value.array->empty()); +dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); + +o->write_character(']'); +} + +return; +} + +case value_t::string: +{ +o->write_character('\"'); +dump_escaped(*val.m_value.string, ensure_ascii); +o->write_character('\"'); +return; +} + +case value_t::boolean: +{ +if (val.m_value.boolean) +{ +o->write_characters("true", 4); +} +else +{ +o->write_characters("false", 5); +} +return; +} + +case value_t::number_integer: +{ +dump_integer(val.m_value.number_integer); +return; +} + +case value_t::number_unsigned: +{ +dump_integer(val.m_value.number_unsigned); +return; +} + +case value_t::number_float: +{ +dump_float(val.m_value.number_float); +return; +} + +case value_t::discarded: +{ +o->write_characters("", 11); +return; +} + +case value_t::null: +{ +o->write_characters("null", 4); +return; +} +} +} + +private: +/*! + @brief dump escaped string + + Escape a string by replacing certain special characters by a sequence of an + escape character (backslash) and another character and other control + characters by a sequence of "\u" followed by a four-digit hex + representation. The escaped string is written to output stream @a o. + + @param[in] s the string to escape + @param[in] ensure_ascii whether to escape non-ASCII characters with + \uXXXX sequences + + @complexity Linear in the length of string @a s. + */ +void dump_escaped(const string_t& s, const bool ensure_ascii) +{ +uint32_t codepoint; +uint8_t state = UTF8_ACCEPT; +std::size_t bytes = 0; // number of bytes written to string_buffer + +for (std::size_t i = 0; i < s.size(); ++i) +{ +const auto byte = static_cast(s[i]); + +switch (decode(state, codepoint, byte)) +{ +case UTF8_ACCEPT: // decode found a new code point +{ +switch (codepoint) +{ +case 0x08: // backspace +{ +string_buffer[bytes++] = '\\'; +string_buffer[bytes++] = 'b'; +break; +} + +case 0x09: // horizontal tab +{ +string_buffer[bytes++] = '\\'; +string_buffer[bytes++] = 't'; +break; +} + +case 0x0A: // newline +{ +string_buffer[bytes++] = '\\'; +string_buffer[bytes++] = 'n'; +break; +} + +case 0x0C: // formfeed +{ +string_buffer[bytes++] = '\\'; +string_buffer[bytes++] = 'f'; +break; +} + +case 0x0D: // carriage return +{ +string_buffer[bytes++] = '\\'; +string_buffer[bytes++] = 'r'; +break; +} + +case 0x22: // quotation mark +{ +string_buffer[bytes++] = '\\'; +string_buffer[bytes++] = '\"'; +break; +} + +case 0x5C: // reverse solidus +{ +string_buffer[bytes++] = '\\'; +string_buffer[bytes++] = '\\'; +break; +} + +default: +{ +// escape control characters (0x00..0x1F) or, if +// ensure_ascii parameter is used, non-ASCII characters +if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F))) +{ +if (codepoint <= 0xFFFF) +{ +std::snprintf(string_buffer.data() + bytes, 7, "\\u%04x", +static_cast(codepoint)); +bytes += 6; +} +else +{ +std::snprintf(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", +static_cast(0xD7C0 + (codepoint >> 10)), +static_cast(0xDC00 + (codepoint & 0x3FF))); +bytes += 12; +} +} +else +{ +// copy byte to buffer (all previous bytes +// been copied have in default case above) +string_buffer[bytes++] = s[i]; +} +break; +} +} + +// write buffer and reset index; there must be 13 bytes +// left, as this is the maximal number of bytes to be +// written ("\uxxxx\uxxxx\0") for one code point +if (string_buffer.size() - bytes < 13) +{ +o->write_characters(string_buffer.data(), bytes); +bytes = 0; +} +break; +} + +case UTF8_REJECT: // decode found invalid UTF-8 byte +{ +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(byte); +JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + ss.str())); +} + +default: // decode found yet incomplete multi-byte code point +{ +if (not ensure_ascii) +{ +// code point will not be escaped - copy byte to buffer +string_buffer[bytes++] = s[i]; +} +break; +} +} +} + +if (JSON_LIKELY(state == UTF8_ACCEPT)) +{ +// write buffer +if (bytes > 0) +{ +o->write_characters(string_buffer.data(), bytes); +} +} +else +{ +// we finish reading, but do not accept: string was incomplete +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(static_cast(s.back())); +JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + ss.str())); +} +} + +/*! + @brief dump an integer + + Dump a given integer to output stream @a o. Works internally with + @a number_buffer. + + @param[in] x integer number (signed or unsigned) to dump + @tparam NumberType either @a number_integer_t or @a number_unsigned_t + */ +template::value or +std::is_same::value, +int> = 0> +void dump_integer(NumberType x) +{ +// special case for "0" +if (x == 0) +{ +o->write_character('0'); +return; +} + +const bool is_negative = (x <= 0) and (x != 0); // see issue #755 +std::size_t i = 0; + +while (x != 0) +{ +// spare 1 byte for '\0' +assert(i < number_buffer.size() - 1); + +const auto digit = std::labs(static_cast(x % 10)); +number_buffer[i++] = static_cast('0' + digit); +x /= 10; +} + +if (is_negative) +{ +// make sure there is capacity for the '-' +assert(i < number_buffer.size() - 2); +number_buffer[i++] = '-'; +} + +std::reverse(number_buffer.begin(), number_buffer.begin() + i); +o->write_characters(number_buffer.data(), i); +} + +/*! + @brief dump a floating-point number + + Dump a given floating-point number to output stream @a o. Works internally + with @a number_buffer. + + @param[in] x floating-point number to dump + */ +void dump_float(number_float_t x) +{ +// NaN / inf +if (not std::isfinite(x)) +{ +o->write_characters("null", 4); +return; +} + +// If number_float_t is an IEEE-754 single or double precision number, +// use the Grisu2 algorithm to produce short numbers which are +// guaranteed to round-trip, using strtof and strtod, resp. +// +// NB: The test below works if == . +static constexpr bool is_ieee_single_or_double += (std::numeric_limits::is_iec559 and std::numeric_limits::digits == 24 and std::numeric_limits::max_exponent == 128) or +(std::numeric_limits::is_iec559 and std::numeric_limits::digits == 53 and std::numeric_limits::max_exponent == 1024); + +dump_float(x, std::integral_constant()); +} + +void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/) +{ +char* begin = number_buffer.data(); +char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x); + +o->write_characters(begin, static_cast(end - begin)); +} + +void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) +{ +// get number of digits for a float -> text -> float round-trip +static constexpr auto d = std::numeric_limits::max_digits10; + +// the actual conversion +std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x); + +// negative value indicates an error +assert(len > 0); +// check if buffer was large enough +assert(static_cast(len) < number_buffer.size()); + +// erase thousands separator +if (thousands_sep != '\0') +{ +const auto end = std::remove(number_buffer.begin(), +number_buffer.begin() + len, thousands_sep); +std::fill(end, number_buffer.end(), '\0'); +assert((end - number_buffer.begin()) <= len); +len = (end - number_buffer.begin()); +} + +// convert decimal point to '.' +if (decimal_point != '\0' and decimal_point != '.') +{ +const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); +if (dec_pos != number_buffer.end()) +{ +*dec_pos = '.'; +} +} + +o->write_characters(number_buffer.data(), static_cast(len)); + +// determine if need to append ".0" +const bool value_is_int_like = +std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, +[](char c) +{ +return (c == '.' or c == 'e'); +}); + +if (value_is_int_like) +{ +o->write_characters(".0", 2); +} +} + +/*! + @brief check whether a string is UTF-8 encoded + + The function checks each byte of a string whether it is UTF-8 encoded. The + result of the check is stored in the @a state parameter. The function must + be called initially with state 0 (accept). State 1 means the string must + be rejected, because the current byte is not allowed. If the string is + completely processed, but the state is non-zero, the string ended + prematurely; that is, the last byte indicated more bytes should have + followed. + + @param[in,out] state the state of the decoding + @param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT) + @param[in] byte next byte to decode + @return new state + + @note The function has been edited: a std::array is used. + + @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann + @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + */ +static uint8_t decode(uint8_t& state, uint32_t& codep, const uint8_t byte) noexcept +{ +static const std::array utf8d = +{ +{ +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF +8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF +0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF +0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF +0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 +1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 +1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 +1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 +} +}; + +const uint8_t type = utf8d[byte]; + +codep = (state != UTF8_ACCEPT) +? (byte & 0x3fu) | (codep << 6) +: static_cast(0xff >> type) & (byte); + +state = utf8d[256u + state * 16u + type]; +return state; +} + +private: +/// the output of the serializer +output_adapter_t o = nullptr; + +/// a (hopefully) large enough character buffer +std::array number_buffer{{}}; + +/// the locale +const std::lconv* loc = nullptr; +/// the locale's thousand separator character +const char thousands_sep = '\0'; +/// the locale's decimal point character +const char decimal_point = '\0'; + +/// string buffer +std::array string_buffer{{}}; + +/// the indentation character +const char indent_char; +/// the indentation string +string_t indent_string; +}; +} +} + +// #include + + +#include +#include + +namespace nlohmann +{ +namespace detail +{ +template +class json_ref +{ +public: +using value_type = BasicJsonType; + +json_ref(value_type&& value) +: owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true) +{} + +json_ref(const value_type& value) +: value_ref(const_cast(&value)), is_rvalue(false) +{} + +json_ref(std::initializer_list init) +: owned_value(init), value_ref(&owned_value), is_rvalue(true) +{} + +template +json_ref(Args&& ... args) +: owned_value(std::forward(args)...), value_ref(&owned_value), is_rvalue(true) +{} + +// class should be movable only +json_ref(json_ref&&) = default; +json_ref(const json_ref&) = delete; +json_ref& operator=(const json_ref&) = delete; + +value_type moved_or_copied() const +{ +if (is_rvalue) +{ +return std::move(*value_ref); +} +return *value_ref; +} + +value_type const& operator*() const +{ +return *static_cast(value_ref); +} + +value_type const* operator->() const +{ +return static_cast(value_ref); +} + +private: +mutable value_type owned_value = nullptr; +value_type* value_ref = nullptr; +const bool is_rvalue; +}; +} +} + +// #include + + +#include // assert +#include // accumulate +#include // string +#include // vector + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +template +class json_pointer +{ +// allow basic_json to access private members +NLOHMANN_BASIC_JSON_TPL_DECLARATION +friend class basic_json; + +public: +/*! + @brief create JSON pointer + + Create a JSON pointer according to the syntax described in + [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). + + @param[in] s string representing the JSON pointer; if omitted, the empty + string is assumed which references the whole JSON value + + @throw parse_error.107 if the given JSON pointer @a s is nonempty and does + not begin with a slash (`/`); see example below + + @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is + not followed by `0` (representing `~`) or `1` (representing `/`); see + example below + + @liveexample{The example shows the construction several valid JSON pointers + as well as the exceptional behavior.,json_pointer} + + @since version 2.0.0 + */ +explicit json_pointer(const std::string& s = "") +: reference_tokens(split(s)) +{} + +/*! + @brief return a string representation of the JSON pointer + + @invariant For each JSON pointer `ptr`, it holds: + @code {.cpp} + ptr == json_pointer(ptr.to_string()); + @endcode + + @return a string representation of the JSON pointer + + @liveexample{The example shows the result of `to_string`., + json_pointer__to_string} + + @since version 2.0.0 + */ +std::string to_string() const noexcept +{ +return std::accumulate(reference_tokens.begin(), reference_tokens.end(), +std::string{}, +[](const std::string & a, const std::string & b) +{ +return a + "/" + escape(b); +}); +} + +/// @copydoc to_string() +operator std::string() const +{ +return to_string(); +} + +/*! + @param[in] s reference token to be converted into an array index + + @return integer representation of @a s + + @throw out_of_range.404 if string @a s could not be converted to an integer + */ +static int array_index(const std::string& s) +{ +std::size_t processed_chars = 0; +const int res = std::stoi(s, &processed_chars); + +// check if the string was completely read +if (JSON_UNLIKELY(processed_chars != s.size())) +{ +JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); +} + +return res; +} + +private: +/*! + @brief remove and return last reference pointer + @throw out_of_range.405 if JSON pointer has no parent + */ +std::string pop_back() +{ +if (JSON_UNLIKELY(is_root())) +{ +JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); +} + +auto last = reference_tokens.back(); +reference_tokens.pop_back(); +return last; +} + +/// return whether pointer points to the root document +bool is_root() const +{ +return reference_tokens.empty(); +} + +json_pointer top() const +{ +if (JSON_UNLIKELY(is_root())) +{ +JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); +} + +json_pointer result = *this; +result.reference_tokens = {reference_tokens[0]}; +return result; +} + +/*! + @brief create and return a reference to the pointed to value + + @complexity Linear in the number of reference tokens. + + @throw parse_error.109 if array index is not a number + @throw type_error.313 if value cannot be unflattened + */ +BasicJsonType& get_and_create(BasicJsonType& j) const +{ +using size_type = typename BasicJsonType::size_type; +auto result = &j; + +// in case no reference tokens exist, return a reference to the JSON value +// j which will be overwritten by a primitive value +for (const auto& reference_token : reference_tokens) +{ +switch (result->m_type) +{ +case detail::value_t::null: +{ +if (reference_token == "0") +{ +// start a new array if reference token is 0 +result = &result->operator[](0); +} +else +{ +// start a new object otherwise +result = &result->operator[](reference_token); +} +break; +} + +case detail::value_t::object: +{ +// create an entry in the object +result = &result->operator[](reference_token); +break; +} + +case detail::value_t::array: +{ +// create an entry in the array +JSON_TRY +{ +result = &result->operator[](static_cast(array_index(reference_token))); +} +JSON_CATCH(std::invalid_argument&) +{ +JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); +} +break; +} + +/* + The following code is only reached if there exists a reference + token _and_ the current value is primitive. In this case, we have + an error situation, because primitive values may only occur as + single value; that is, with an empty list of reference tokens. + */ +default: +JSON_THROW(detail::type_error::create(313, "invalid value to unflatten")); +} +} + +return *result; +} + +/*! + @brief return a reference to the pointed to value + + @note This version does not throw if a value is not present, but tries to + create nested values instead. For instance, calling this function + with pointer `"/this/that"` on a null value is equivalent to calling + `operator[]("this").operator[]("that")` on that value, effectively + changing the null value to an object. + + @param[in] ptr a JSON value + + @return reference to the JSON value pointed to by the JSON pointer + + @complexity Linear in the length of the JSON pointer. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + */ +BasicJsonType& get_unchecked(BasicJsonType* ptr) const +{ +using size_type = typename BasicJsonType::size_type; +for (const auto& reference_token : reference_tokens) +{ +// convert null values to arrays or objects before continuing +if (ptr->m_type == detail::value_t::null) +{ +// check if reference token is a number +const bool nums = +std::all_of(reference_token.begin(), reference_token.end(), +[](const char x) +{ +return (x >= '0' and x <= '9'); +}); + +// change value to array for numbers or "-" or to object otherwise +*ptr = (nums or reference_token == "-") +? detail::value_t::array +: detail::value_t::object; +} + +switch (ptr->m_type) +{ +case detail::value_t::object: +{ +// use unchecked object access +ptr = &ptr->operator[](reference_token); +break; +} + +case detail::value_t::array: +{ +// error condition (cf. RFC 6901, Sect. 4) +if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) +{ +JSON_THROW(detail::parse_error::create(106, 0, +"array index '" + reference_token + +"' must not begin with '0'")); +} + +if (reference_token == "-") +{ +// explicitly treat "-" as index beyond the end +ptr = &ptr->operator[](ptr->m_value.array->size()); +} +else +{ +// convert array index to number; unchecked access +JSON_TRY +{ +ptr = &ptr->operator[]( +static_cast(array_index(reference_token))); +} +JSON_CATCH(std::invalid_argument&) +{ +JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); +} +} +break; +} + +default: +JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); +} +} + +return *ptr; +} + +/*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ +BasicJsonType& get_checked(BasicJsonType* ptr) const +{ +using size_type = typename BasicJsonType::size_type; +for (const auto& reference_token : reference_tokens) +{ +switch (ptr->m_type) +{ +case detail::value_t::object: +{ +// note: at performs range check +ptr = &ptr->at(reference_token); +break; +} + +case detail::value_t::array: +{ +if (JSON_UNLIKELY(reference_token == "-")) +{ +// "-" always fails the range check +JSON_THROW(detail::out_of_range::create(402, +"array index '-' (" + std::to_string(ptr->m_value.array->size()) + +") is out of range")); +} + +// error condition (cf. RFC 6901, Sect. 4) +if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) +{ +JSON_THROW(detail::parse_error::create(106, 0, +"array index '" + reference_token + +"' must not begin with '0'")); +} + +// note: at performs range check +JSON_TRY +{ +ptr = &ptr->at(static_cast(array_index(reference_token))); +} +JSON_CATCH(std::invalid_argument&) +{ +JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); +} +break; +} + +default: +JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); +} +} + +return *ptr; +} + +/*! + @brief return a const reference to the pointed to value + + @param[in] ptr a JSON value + + @return const reference to the JSON value pointed to by the JSON + pointer + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ +const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const +{ +using size_type = typename BasicJsonType::size_type; +for (const auto& reference_token : reference_tokens) +{ +switch (ptr->m_type) +{ +case detail::value_t::object: +{ +// use unchecked object access +ptr = &ptr->operator[](reference_token); +break; +} + +case detail::value_t::array: +{ +if (JSON_UNLIKELY(reference_token == "-")) +{ +// "-" cannot be used for const access +JSON_THROW(detail::out_of_range::create(402, +"array index '-' (" + std::to_string(ptr->m_value.array->size()) + +") is out of range")); +} + +// error condition (cf. RFC 6901, Sect. 4) +if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) +{ +JSON_THROW(detail::parse_error::create(106, 0, +"array index '" + reference_token + +"' must not begin with '0'")); +} + +// use unchecked array access +JSON_TRY +{ +ptr = &ptr->operator[]( +static_cast(array_index(reference_token))); +} +JSON_CATCH(std::invalid_argument&) +{ +JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); +} +break; +} + +default: +JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); +} +} + +return *ptr; +} + +/*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ +const BasicJsonType& get_checked(const BasicJsonType* ptr) const +{ +using size_type = typename BasicJsonType::size_type; +for (const auto& reference_token : reference_tokens) +{ +switch (ptr->m_type) +{ +case detail::value_t::object: +{ +// note: at performs range check +ptr = &ptr->at(reference_token); +break; +} + +case detail::value_t::array: +{ +if (JSON_UNLIKELY(reference_token == "-")) +{ +// "-" always fails the range check +JSON_THROW(detail::out_of_range::create(402, +"array index '-' (" + std::to_string(ptr->m_value.array->size()) + +") is out of range")); +} + +// error condition (cf. RFC 6901, Sect. 4) +if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) +{ +JSON_THROW(detail::parse_error::create(106, 0, +"array index '" + reference_token + +"' must not begin with '0'")); +} + +// note: at performs range check +JSON_TRY +{ +ptr = &ptr->at(static_cast(array_index(reference_token))); +} +JSON_CATCH(std::invalid_argument&) +{ +JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); +} +break; +} + +default: +JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); +} +} + +return *ptr; +} + +/*! + @brief split the string input to reference tokens + + @note This function is only called by the json_pointer constructor. + All exceptions below are documented there. + + @throw parse_error.107 if the pointer is not empty or begins with '/' + @throw parse_error.108 if character '~' is not followed by '0' or '1' + */ +static std::vector split(const std::string& reference_string) +{ +std::vector result; + +// special case: empty reference string -> no reference tokens +if (reference_string.empty()) +{ +return result; +} + +// check if nonempty reference string begins with slash +if (JSON_UNLIKELY(reference_string[0] != '/')) +{ +JSON_THROW(detail::parse_error::create(107, 1, +"JSON pointer must be empty or begin with '/' - was: '" + +reference_string + "'")); +} + +// extract the reference tokens: +// - slash: position of the last read slash (or end of string) +// - start: position after the previous slash +for ( +// search for the first slash after the first character +std::size_t slash = reference_string.find_first_of('/', 1), +// set the beginning of the first reference token +start = 1; +// we can stop if start == string::npos+1 = 0 +start != 0; +// set the beginning of the next reference token +// (will eventually be 0 if slash == std::string::npos) +start = slash + 1, +// find next slash +slash = reference_string.find_first_of('/', start)) +{ +// use the text between the beginning of the reference token +// (start) and the last slash (slash). +auto reference_token = reference_string.substr(start, slash - start); + +// check reference tokens are properly escaped +for (std::size_t pos = reference_token.find_first_of('~'); +pos != std::string::npos; +pos = reference_token.find_first_of('~', pos + 1)) +{ +assert(reference_token[pos] == '~'); + +// ~ must be followed by 0 or 1 +if (JSON_UNLIKELY(pos == reference_token.size() - 1 or +(reference_token[pos + 1] != '0' and +reference_token[pos + 1] != '1'))) +{ +JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'")); +} +} + +// finally, store the reference token +unescape(reference_token); +result.push_back(reference_token); +} + +return result; +} + +/*! + @brief replace all occurrences of a substring by another string + + @param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t + @param[in] f the substring to replace with @a t + @param[in] t the string to replace @a f + + @pre The search string @a f must not be empty. **This precondition is + enforced with an assertion.** + + @since version 2.0.0 + */ +static void replace_substring(std::string& s, const std::string& f, +const std::string& t) +{ +assert(not f.empty()); +for (auto pos = s.find(f); // find first occurrence of f +pos != std::string::npos; // make sure f was found +s.replace(pos, f.size(), t), // replace with t, and +pos = s.find(f, pos + t.size())) // find next occurrence of f +{} +} + +/// escape "~"" to "~0" and "/" to "~1" +static std::string escape(std::string s) +{ +replace_substring(s, "~", "~0"); +replace_substring(s, "/", "~1"); +return s; +} + +/// unescape "~1" to tilde and "~0" to slash (order is important!) +static void unescape(std::string& s) +{ +replace_substring(s, "~1", "/"); +replace_substring(s, "~0", "~"); +} + +/*! + @param[in] reference_string the reference string to the current value + @param[in] value the value to consider + @param[in,out] result the result object to insert values to + + @note Empty objects or arrays are flattened to `null`. + */ +static void flatten(const std::string& reference_string, +const BasicJsonType& value, +BasicJsonType& result) +{ +switch (value.m_type) +{ +case detail::value_t::array: +{ +if (value.m_value.array->empty()) +{ +// flatten empty array as null +result[reference_string] = nullptr; +} +else +{ +// iterate array and use index as reference string +for (std::size_t i = 0; i < value.m_value.array->size(); ++i) +{ +flatten(reference_string + "/" + std::to_string(i), +value.m_value.array->operator[](i), result); +} +} +break; +} + +case detail::value_t::object: +{ +if (value.m_value.object->empty()) +{ +// flatten empty object as null +result[reference_string] = nullptr; +} +else +{ +// iterate object and use keys as reference string +for (const auto& element : *value.m_value.object) +{ +flatten(reference_string + "/" + escape(element.first), element.second, result); +} +} +break; +} + +default: +{ +// add primitive value with its reference string +result[reference_string] = value; +break; +} +} +} + +/*! + @param[in] value flattened JSON + + @return unflattened JSON + + @throw parse_error.109 if array index is not a number + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + @throw type_error.313 if value cannot be unflattened + */ +static BasicJsonType +unflatten(const BasicJsonType& value) +{ +if (JSON_UNLIKELY(not value.is_object())) +{ +JSON_THROW(detail::type_error::create(314, "only objects can be unflattened")); +} + +BasicJsonType result; + +// iterate the JSON object values +for (const auto& element : *value.m_value.object) +{ +if (JSON_UNLIKELY(not element.second.is_primitive())) +{ +JSON_THROW(detail::type_error::create(315, "values in object must be primitive")); +} + +// assign value to reference pointed to by JSON pointer; Note that if +// the JSON pointer is "" (i.e., points to the whole value), function +// get_and_create returns a reference to result itself. An assignment +// will then create a primitive value. +json_pointer(element.first).get_and_create(result) = element.second; +} + +return result; +} + +friend bool operator==(json_pointer const& lhs, +json_pointer const& rhs) noexcept +{ +return (lhs.reference_tokens == rhs.reference_tokens); +} + +friend bool operator!=(json_pointer const& lhs, +json_pointer const& rhs) noexcept +{ +return not (lhs == rhs); +} + +/// the reference tokens +std::vector reference_tokens; +}; +} + +// #include + + +#include + +// #include + +// #include + + +namespace nlohmann +{ +template +struct adl_serializer +{ +/*! + @brief convert a JSON value to any value type + + This function is usually called by the `get()` function of the + @ref basic_json class (either explicit or via conversion operators). + + @param[in] j JSON value to read from + @param[in,out] val value to write to + */ +template +static void from_json(BasicJsonType&& j, ValueType& val) noexcept( +noexcept(::nlohmann::from_json(std::forward(j), val))) +{ +::nlohmann::from_json(std::forward(j), val); +} + +/*! + @brief convert any value type to a JSON value + + This function is usually called by the constructors of the @ref basic_json + class. + + @param[in,out] j JSON value to write to + @param[in] val value to read from + */ +template +static void to_json(BasicJsonType& j, ValueType&& val) noexcept( +noexcept(::nlohmann::to_json(j, std::forward(val)))) +{ +::nlohmann::to_json(j, std::forward(val)); +} +}; +} + + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ + +/*! +@brief a class to store JSON values + +@tparam ObjectType type for JSON objects (`std::map` by default; will be used +in @ref object_t) +@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used +in @ref array_t) +@tparam StringType type for JSON strings and object keys (`std::string` by +default; will be used in @ref string_t) +@tparam BooleanType type for JSON booleans (`bool` by default; will be used +in @ref boolean_t) +@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by +default; will be used in @ref number_integer_t) +@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c +`uint64_t` by default; will be used in @ref number_unsigned_t) +@tparam NumberFloatType type for JSON floating-point numbers (`double` by +default; will be used in @ref number_float_t) +@tparam AllocatorType type of the allocator to use (`std::allocator` by +default) +@tparam JSONSerializer the serializer to resolve internal calls to `to_json()` +and `from_json()` (@ref adl_serializer by default) + +@requirement The class satisfies the following concept requirements: +- Basic + - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): + JSON values can be default constructed. The result will be a JSON null + value. + - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): + A JSON value can be constructed from an rvalue argument. + - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): + A JSON value can be copy-constructed from an lvalue expression. + - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): + A JSON value van be assigned from an rvalue argument. + - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): + A JSON value can be copy-assigned from an lvalue expression. + - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): + JSON values can be destructed. +- Layout + - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): + JSON values have + [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): + All non-static data members are private and standard layout types, the + class has no virtual functions or (virtual) base classes. +- Library-wide + - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): + JSON values can be compared with `==`, see @ref + operator==(const_reference,const_reference). + - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): + JSON values can be compared with `<`, see @ref + operator<(const_reference,const_reference). + - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): + Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of + other compatible types, using unqualified function call @ref swap(). + - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): + JSON values can be compared against `std::nullptr_t` objects which are used + to model the `null` value. +- Container + - [Container](http://en.cppreference.com/w/cpp/concept/Container): + JSON values can be used like STL containers and provide iterator access. + - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); + JSON values can be used like STL containers and provide reverse iterator + access. + +@invariant The member variables @a m_value and @a m_type have the following +relationship: +- If `m_type == value_t::object`, then `m_value.object != nullptr`. +- If `m_type == value_t::array`, then `m_value.array != nullptr`. +- If `m_type == value_t::string`, then `m_value.string != nullptr`. +The invariants are checked by member function assert_invariant(). + +@internal +@note ObjectType trick from http://stackoverflow.com/a/9860911 +@endinternal + +@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange +Format](http://rfc7159.net/rfc7159) + +@since version 1.0.0 + +@nosubgrouping +*/ +NLOHMANN_BASIC_JSON_TPL_DECLARATION +class basic_json +{ +private: +template friend struct detail::external_constructor; +friend ::nlohmann::json_pointer; +friend ::nlohmann::detail::parser; +friend ::nlohmann::detail::serializer; +template +friend class ::nlohmann::detail::iter_impl; +template +friend class ::nlohmann::detail::binary_writer; +template +friend class ::nlohmann::detail::binary_reader; + +/// workaround type for MSVC +using basic_json_t = NLOHMANN_BASIC_JSON_TPL; + +// convenience aliases for types residing in namespace detail; +using lexer = ::nlohmann::detail::lexer; +using parser = ::nlohmann::detail::parser; + +using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; +template +using internal_iterator = ::nlohmann::detail::internal_iterator; +template +using iter_impl = ::nlohmann::detail::iter_impl; +template +using iteration_proxy = ::nlohmann::detail::iteration_proxy; +template using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator; + +template +using output_adapter_t = ::nlohmann::detail::output_adapter_t; + +using binary_reader = ::nlohmann::detail::binary_reader; +template using binary_writer = ::nlohmann::detail::binary_writer; + +using serializer = ::nlohmann::detail::serializer; + +public: +using value_t = detail::value_t; +/// @copydoc nlohmann::json_pointer +using json_pointer = ::nlohmann::json_pointer; +template +using json_serializer = JSONSerializer; +/// helper type for initializer lists of basic_json values +using initializer_list_t = std::initializer_list>; + +//////////////// +// exceptions // +//////////////// + +/// @name exceptions +/// Classes to implement user-defined exceptions. +/// @{ + +/// @copydoc detail::exception +using exception = detail::exception; +/// @copydoc detail::parse_error +using parse_error = detail::parse_error; +/// @copydoc detail::invalid_iterator +using invalid_iterator = detail::invalid_iterator; +/// @copydoc detail::type_error +using type_error = detail::type_error; +/// @copydoc detail::out_of_range +using out_of_range = detail::out_of_range; +/// @copydoc detail::other_error +using other_error = detail::other_error; + +/// @} + + +///////////////////// +// container types // +///////////////////// + +/// @name container types +/// The canonic container types to use @ref basic_json like any other STL +/// container. +/// @{ + +/// the type of elements in a basic_json container +using value_type = basic_json; + +/// the type of an element reference +using reference = value_type&; +/// the type of an element const reference +using const_reference = const value_type&; + +/// a type to represent differences between iterators +using difference_type = std::ptrdiff_t; +/// a type to represent container sizes +using size_type = std::size_t; + +/// the allocator type +using allocator_type = AllocatorType; + +/// the type of an element pointer +using pointer = typename std::allocator_traits::pointer; +/// the type of an element const pointer +using const_pointer = typename std::allocator_traits::const_pointer; + +/// an iterator for a basic_json container +using iterator = iter_impl; +/// a const iterator for a basic_json container +using const_iterator = iter_impl; +/// a reverse iterator for a basic_json container +using reverse_iterator = json_reverse_iterator; +/// a const reverse iterator for a basic_json container +using const_reverse_iterator = json_reverse_iterator; + +/// @} + + +/*! + @brief returns the allocator associated with the container + */ +static allocator_type get_allocator() +{ +return allocator_type(); +} + +/*! + @brief returns version information on the library + + This function returns a JSON object with information about the library, + including the version number and information on the platform and compiler. + + @return JSON object holding version information + key | description + ----------- | --------------- + `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version). + `copyright` | The copyright line for the library as string. + `name` | The name of the library as string. + `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`. + `url` | The URL of the project as string. + `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string). + + @liveexample{The following code shows an example output of the `meta()` + function.,meta} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @complexity Constant. + + @since 2.1.0 + */ +static basic_json meta() +{ +basic_json result; + +result["copyright"] = "(C) 2013-2017 Niels Lohmann"; +result["name"] = "JSON for Modern C++"; +result["url"] = "https://github.com/nlohmann/json"; +result["version"]["string"] = +std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + "." + +std::to_string(NLOHMANN_JSON_VERSION_MINOR) + "." + +std::to_string(NLOHMANN_JSON_VERSION_PATCH); +result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR; +result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR; +result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH; + +#ifdef _WIN32 +result["platform"] = "win32"; +#elif defined __linux__ +result["platform"] = "linux"; +#elif defined __APPLE__ +result["platform"] = "apple"; +#elif defined __unix__ +result["platform"] = "unix"; +#else +result["platform"] = "unknown"; +#endif + +#if defined(__ICC) || defined(__INTEL_COMPILER) +result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; +#elif defined(__clang__) +result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; +#elif defined(__GNUC__) || defined(__GNUG__) +result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; +#elif defined(__HP_cc) || defined(__HP_aCC) +result["compiler"] = "hp" +#elif defined(__IBMCPP__) +result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; +#elif defined(_MSC_VER) +result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; +#elif defined(__PGI) +result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; +#elif defined(__SUNPRO_CC) +result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; +#else +result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; +#endif + +#ifdef __cplusplus +result["compiler"]["c++"] = std::to_string(__cplusplus); +#else +result["compiler"]["c++"] = "unknown"; +#endif +return result; +} + + +/////////////////////////// +// JSON value data types // +/////////////////////////// + +/// @name JSON value data types +/// The data types to store a JSON value. These types are derived from +/// the template arguments passed to class @ref basic_json. +/// @{ + +#if defined(JSON_HAS_CPP_14) +// Use transparent comparator if possible, combined with perfect forwarding +// on find() and count() calls prevents unnecessary string construction. +using object_comparator_t = std::less<>; +#else +using object_comparator_t = std::less; +#endif + +/*! + @brief a type for an object + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: + > An object is an unordered collection of zero or more name/value pairs, + > where a name is a string and a value is a string, number, boolean, null, + > object, or array. + + To store objects in C++, a type is defined by the template parameters + described below. + + @tparam ObjectType the container to store objects (e.g., `std::map` or + `std::unordered_map`) + @tparam StringType the type of the keys or names (e.g., `std::string`). + The comparison function `std::less` is used to order elements + inside the container. + @tparam AllocatorType the allocator to use for objects (e.g., + `std::allocator`) + + #### Default type + + With the default values for @a ObjectType (`std::map`), @a StringType + (`std::string`), and @a AllocatorType (`std::allocator`), the default + value for @a object_t is: + + @code {.cpp} + std::map< + std::string, // key_type + basic_json, // value_type + std::less, // key_compare + std::allocator> // allocator_type + > + @endcode + + #### Behavior + + The choice of @a object_t influences the behavior of the JSON class. With + the default type, objects have the following behavior: + + - When all names are unique, objects will be interoperable in the sense + that all software implementations receiving that object will agree on + the name-value mappings. + - When the names within an object are not unique, later stored name/value + pairs overwrite previously stored name/value pairs, leaving the used + names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will + be treated as equal and both stored as `{"key": 1}`. + - Internally, name/value pairs are stored in lexicographical order of the + names. Objects will also be serialized (see @ref dump) in this order. + For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored + and serialized as `{"a": 2, "b": 1}`. + - When comparing objects, the order of the name/value pairs is irrelevant. + This makes objects interoperable in the sense that they will not be + affected by these differences. For instance, `{"b": 1, "a": 2}` and + `{"a": 2, "b": 1}` will be treated as equal. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the object's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON object. + + #### Storage + + Objects are stored as pointers in a @ref basic_json type. That is, for any + access to object values, a pointer of type `object_t*` must be + dereferenced. + + @sa @ref array_t -- type for an array value + + @since version 1.0.0 + + @note The order name/value pairs are added to the object is *not* + preserved by the library. Therefore, iterating an object may return + name/value pairs in a different order than they were originally stored. In + fact, keys will be traversed in alphabetical order as `std::map` with + `std::less` is used by default. Please note this behavior conforms to [RFC + 7159](http://rfc7159.net/rfc7159), because any order implements the + specified "unordered" nature of JSON objects. + */ +using object_t = ObjectType>>; + +/*! + @brief a type for an array + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: + > An array is an ordered sequence of zero or more values. + + To store objects in C++, a type is defined by the template parameters + explained below. + + @tparam ArrayType container type to store arrays (e.g., `std::vector` or + `std::list`) + @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) + + #### Default type + + With the default values for @a ArrayType (`std::vector`) and @a + AllocatorType (`std::allocator`), the default value for @a array_t is: + + @code {.cpp} + std::vector< + basic_json, // value_type + std::allocator // allocator_type + > + @endcode + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the array's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON array. + + #### Storage + + Arrays are stored as pointers in a @ref basic_json type. That is, for any + access to array values, a pointer of type `array_t*` must be dereferenced. + + @sa @ref object_t -- type for an object value + + @since version 1.0.0 + */ +using array_t = ArrayType>; + +/*! + @brief a type for a string + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: + > A string is a sequence of zero or more Unicode characters. + + To store objects in C++, a type is defined by the template parameter + described below. Unicode values are split by the JSON class into + byte-sized characters during deserialization. + + @tparam StringType the container to store strings (e.g., `std::string`). + Note this container is used for keys/names in objects, see @ref object_t. + + #### Default type + + With the default values for @a StringType (`std::string`), the default + value for @a string_t is: + + @code {.cpp} + std::string + @endcode + + #### Encoding + + Strings are stored in UTF-8 encoding. Therefore, functions like + `std::string::size()` or `std::string::length()` return the number of + bytes in the string rather than the number of characters or glyphs. + + #### String comparison + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > Software implementations are typically required to test names of object + > members for equality. Implementations that transform the textual + > representation into sequences of Unicode code units and then perform the + > comparison numerically, code unit by code unit, are interoperable in the + > sense that implementations will agree in all cases on equality or + > inequality of two strings. For example, implementations that compare + > strings with escaped characters unconverted may incorrectly find that + > `"a\\b"` and `"a\u005Cb"` are not equal. + + This implementation is interoperable as it does compare strings code unit + by code unit. + + #### Storage + + String values are stored as pointers in a @ref basic_json type. That is, + for any access to string values, a pointer of type `string_t*` must be + dereferenced. + + @since version 1.0.0 + */ +using string_t = StringType; + +/*! + @brief a type for a boolean + + [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a + type which differentiates the two literals `true` and `false`. + + To store objects in C++, a type is defined by the template parameter @a + BooleanType which chooses the type to use. + + #### Default type + + With the default values for @a BooleanType (`bool`), the default value for + @a boolean_t is: + + @code {.cpp} + bool + @endcode + + #### Storage + + Boolean values are stored directly inside a @ref basic_json type. + + @since version 1.0.0 + */ +using boolean_t = BooleanType; + +/*! + @brief a type for a number (integer) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store integer numbers in C++, a type is defined by the template + parameter @a NumberIntegerType which chooses the type to use. + + #### Default type + + With the default values for @a NumberIntegerType (`int64_t`), the default + value for @a number_integer_t is: + + @code {.cpp} + int64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `9223372036854775807` (INT64_MAX) and the minimal integer number + that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers + that are out of range will yield over/underflow when used in a + constructor. During deserialization, too large or small integer numbers + will be automatically be stored as @ref number_unsigned_t or @ref + number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange of the exactly supported range [INT64_MIN, + INT64_MAX], this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ +using number_integer_t = NumberIntegerType; + +/*! + @brief a type for a number (unsigned) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store unsigned integer numbers in C++, a type is defined by the + template parameter @a NumberUnsignedType which chooses the type to use. + + #### Default type + + With the default values for @a NumberUnsignedType (`uint64_t`), the + default value for @a number_unsigned_t is: + + @code {.cpp} + uint64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `18446744073709551615` (UINT64_MAX) and the minimal integer + number that can be stored is `0`. Integer numbers that are out of range + will yield over/underflow when used in a constructor. During + deserialization, too large or small integer numbers will be automatically + be stored as @ref number_integer_t or @ref number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange (when considered in conjunction with the + number_integer_t type) of the exactly supported range [0, UINT64_MAX], + this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + @sa @ref number_integer_t -- type for number values (integer) + + @since version 2.0.0 + */ +using number_unsigned_t = NumberUnsignedType; + +/*! + @brief a type for a number (floating-point) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store floating-point numbers in C++, a type is defined by the template + parameter @a NumberFloatType which chooses the type to use. + + #### Default type + + With the default values for @a NumberFloatType (`double`), the default + value for @a number_float_t is: + + @code {.cpp} + double + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in floating-point literals will be ignored. Internally, + the value will be stored as decimal number. For instance, the C++ + floating-point literal `01.2` will be serialized to `1.2`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > This specification allows implementations to set limits on the range and + > precision of numbers accepted. Since software that implements IEEE + > 754-2008 binary64 (double precision) numbers is generally available and + > widely used, good interoperability can be achieved by implementations + > that expect no more precision or range than these provide, in the sense + > that implementations will approximate JSON numbers within the expected + > precision. + + This implementation does exactly follow this approach, as it uses double + precision floating-point numbers. Note values smaller than + `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` + will be stored as NaN internally and be serialized to `null`. + + #### Storage + + Floating-point number values are stored directly inside a @ref basic_json + type. + + @sa @ref number_integer_t -- type for number values (integer) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ +using number_float_t = NumberFloatType; + +/// @} + +private: + +/// helper for exception-safe object creation +template +static T* create(Args&& ... args) +{ +AllocatorType alloc; +using AllocatorTraits = std::allocator_traits>; + +auto deleter = [&](T * object) +{ +AllocatorTraits::deallocate(alloc, object, 1); +}; +std::unique_ptr object(AllocatorTraits::allocate(alloc, 1), deleter); +AllocatorTraits::construct(alloc, object.get(), std::forward(args)...); +assert(object != nullptr); +return object.release(); +} + +//////////////////////// +// JSON value storage // +//////////////////////// + +/*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. This + union combines the different storage types for the JSON value types + defined in @ref value_t. + + JSON type | value_t type | used type + --------- | --------------- | ------------------------ + object | object | pointer to @ref object_t + array | array | pointer to @ref array_t + string | string | pointer to @ref string_t + boolean | boolean | @ref boolean_t + number | number_integer | @ref number_integer_t + number | number_unsigned | @ref number_unsigned_t + number | number_float | @ref number_float_t + null | null | *no value is stored* + + @note Variable-length types (objects, arrays, and strings) are stored as + pointers. The size of the union should not exceed 64 bits if the default + value types are used. + + @since version 1.0.0 + */ +union json_value +{ +/// object (stored with pointer to save storage) +object_t* object; +/// array (stored with pointer to save storage) +array_t* array; +/// string (stored with pointer to save storage) +string_t* string; +/// boolean +boolean_t boolean; +/// number (integer) +number_integer_t number_integer; +/// number (unsigned integer) +number_unsigned_t number_unsigned; +/// number (floating-point) +number_float_t number_float; + +/// default constructor (for null values) +json_value() = default; +/// constructor for booleans +json_value(boolean_t v) noexcept : boolean(v) {} +/// constructor for numbers (integer) +json_value(number_integer_t v) noexcept : number_integer(v) {} +/// constructor for numbers (unsigned) +json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} +/// constructor for numbers (floating-point) +json_value(number_float_t v) noexcept : number_float(v) {} +/// constructor for empty values of a given type +json_value(value_t t) +{ +switch (t) +{ +case value_t::object: +{ +object = create(); +break; +} + +case value_t::array: +{ +array = create(); +break; +} + +case value_t::string: +{ +string = create(""); +break; +} + +case value_t::boolean: +{ +boolean = boolean_t(false); +break; +} + +case value_t::number_integer: +{ +number_integer = number_integer_t(0); +break; +} + +case value_t::number_unsigned: +{ +number_unsigned = number_unsigned_t(0); +break; +} + +case value_t::number_float: +{ +number_float = number_float_t(0.0); +break; +} + +case value_t::null: +{ +object = nullptr; // silence warning, see #821 +break; +} + +default: +{ +object = nullptr; // silence warning, see #821 +if (JSON_UNLIKELY(t == value_t::null)) +{ +JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.1.0")); // LCOV_EXCL_LINE +} +break; +} +} +} + +/// constructor for strings +json_value(const string_t& value) +{ +string = create(value); +} + +/// constructor for rvalue strings +json_value(string_t&& value) +{ +string = create(std::move(value)); +} + +/// constructor for objects +json_value(const object_t& value) +{ +object = create(value); +} + +/// constructor for rvalue objects +json_value(object_t&& value) +{ +object = create(std::move(value)); +} + +/// constructor for arrays +json_value(const array_t& value) +{ +array = create(value); +} + +/// constructor for rvalue arrays +json_value(array_t&& value) +{ +array = create(std::move(value)); +} + +void destroy(value_t t) noexcept +{ +switch (t) +{ +case value_t::object: +{ +AllocatorType alloc; +std::allocator_traits::destroy(alloc, object); +std::allocator_traits::deallocate(alloc, object, 1); +break; +} + +case value_t::array: +{ +AllocatorType alloc; +std::allocator_traits::destroy(alloc, array); +std::allocator_traits::deallocate(alloc, array, 1); +break; +} + +case value_t::string: +{ +AllocatorType alloc; +std::allocator_traits::destroy(alloc, string); +std::allocator_traits::deallocate(alloc, string, 1); +break; +} + +default: +{ +break; +} +} +} +}; + +/*! + @brief checks the class invariants + + This function asserts the class invariants. It needs to be called at the + end of every constructor to make sure that created objects respect the + invariant. Furthermore, it has to be called each time the type of a JSON + value is changed, because the invariant expresses a relationship between + @a m_type and @a m_value. + */ +void assert_invariant() const noexcept +{ +assert(m_type != value_t::object or m_value.object != nullptr); +assert(m_type != value_t::array or m_value.array != nullptr); +assert(m_type != value_t::string or m_value.string != nullptr); +} + +public: +////////////////////////// +// JSON parser callback // +////////////////////////// + +/*! + @brief parser event types + + The parser callback distinguishes the following events: + - `object_start`: the parser read `{` and started to process a JSON object + - `key`: the parser read a key of a value in an object + - `object_end`: the parser read `}` and finished processing a JSON object + - `array_start`: the parser read `[` and started to process a JSON array + - `array_end`: the parser read `]` and finished processing a JSON array + - `value`: the parser finished reading a JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + @sa @ref parser_callback_t for more information and examples + */ +using parse_event_t = typename parser::parse_event_t; + +/*! + @brief per-element parser callback type + + With a parser callback function, the result of parsing a JSON text can be + influenced. When passed to @ref parse, it is called on certain events + (passed as @ref parse_event_t via parameter @a event) with a set recursion + depth @a depth and context JSON value @a parsed. The return value of the + callback function is a boolean indicating whether the element that emitted + the callback shall be kept or not. + + We distinguish six scenarios (determined by the event type) in which the + callback function can be called. The following table describes the values + of the parameters @a depth, @a event, and @a parsed. + + parameter @a event | description | parameter @a depth | parameter @a parsed + ------------------ | ----------- | ------------------ | ------------------- + parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded + parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key + parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object + parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded + parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array + parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + Discarding a value (i.e., returning `false`) has different effects + depending on the context in which function was called: + + - Discarded values in structured types are skipped. That is, the parser + will behave as if the discarded value was never read. + - In case a value outside a structured type is skipped, it is replaced + with `null`. This case happens if the top-level element is skipped. + + @param[in] depth the depth of the recursion during parsing + + @param[in] event an event of type parse_event_t indicating the context in + the callback function has been called + + @param[in,out] parsed the current intermediate parse result; note that + writing to this value has no effect for parse_event_t::key events + + @return Whether the JSON value which called the function during parsing + should be kept (`true`) or not (`false`). In the latter case, it is either + skipped completely or replaced by an empty discarded object. + + @sa @ref parse for examples + + @since version 1.0.0 + */ +using parser_callback_t = typename parser::parser_callback_t; + + +////////////////// +// constructors // +////////////////// + +/// @name constructors and destructors +/// Constructors of class @ref basic_json, copy/move constructor, copy +/// assignment, static functions creating objects, and the destructor. +/// @{ + +/*! + @brief create an empty value with a given type + + Create an empty JSON value with a given type. The value will be default + initialized with an empty value which depends on the type: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @param[in] v the type of the value to create + + @complexity Constant. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows the constructor for different @ref + value_t values,basic_json__value_t} + + @sa @ref clear() -- restores the postcondition of this constructor + + @since version 1.0.0 + */ +basic_json(const value_t v) +: m_type(v), m_value(v) +{ +assert_invariant(); +} + +/*! + @brief create a null object + + Create a `null` JSON value. It either takes a null pointer as parameter + (explicitly creating `null`) or no parameter (implicitly creating `null`). + The passed null pointer itself is not read -- it is only used to choose + the right constructor. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @liveexample{The following code shows the constructor with and without a + null pointer parameter.,basic_json__nullptr_t} + + @since version 1.0.0 + */ +basic_json(std::nullptr_t = nullptr) noexcept +: basic_json(value_t::null) +{ +assert_invariant(); +} + +/*! + @brief create a JSON value + + This is a "catch all" constructor for all compatible JSON types; that is, + types for which a `to_json()` method exists. The constructor forwards the + parameter @a val to that method (to `json_serializer::to_json` method + with `U = uncvref_t`, to be exact). + + Template type @a CompatibleType includes, but is not limited to, the + following types: + - **arrays**: @ref array_t and all kinds of compatible containers such as + `std::vector`, `std::deque`, `std::list`, `std::forward_list`, + `std::array`, `std::valarray`, `std::set`, `std::unordered_set`, + `std::multiset`, and `std::unordered_multiset` with a `value_type` from + which a @ref basic_json value can be constructed. + - **objects**: @ref object_t and all kinds of compatible associative + containers such as `std::map`, `std::unordered_map`, `std::multimap`, + and `std::unordered_multimap` with a `key_type` compatible to + @ref string_t and a `value_type` from which a @ref basic_json value can + be constructed. + - **strings**: @ref string_t, string literals, and all compatible string + containers can be used. + - **numbers**: @ref number_integer_t, @ref number_unsigned_t, + @ref number_float_t, and all convertible number types such as `int`, + `size_t`, `int64_t`, `float` or `double` can be used. + - **boolean**: @ref boolean_t / `bool` can be used. + + See the examples below. + + @tparam CompatibleType a type such that: + - @a CompatibleType is not derived from `std::istream`, + - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move + constructors), + - @a CompatibleType is not a @ref basic_json nested type (e.g., + @ref json_pointer, @ref iterator, etc ...) + - @ref @ref json_serializer has a + `to_json(basic_json_t&, CompatibleType&&)` method + + @tparam U = `uncvref_t` + + @param[in] val the value to be forwarded to the respective constructor + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. + + @liveexample{The following code shows the constructor with several + compatible types.,basic_json__CompatibleType} + + @since version 2.1.0 + */ +template , +detail::enable_if_t< +detail::is_compatible_type::value, int> = 0> +basic_json(CompatibleType && val) noexcept(noexcept( +JSONSerializer::to_json(std::declval(), +std::forward(val)))) +{ +JSONSerializer::to_json(*this, std::forward(val)); +assert_invariant(); +} + +/*! + @brief create a container (array or object) from an initializer list + + Creates a JSON value of type array or object from the passed initializer + list @a init. In case @a type_deduction is `true` (default), the type of + the JSON value to be created is deducted from the initializer list @a init + according to the following rules: + + 1. If the list is empty, an empty JSON object value `{}` is created. + 2. If the list consists of pairs whose first element is a string, a JSON + object value is created where the first elements of the pairs are + treated as keys and the second elements are as values. + 3. In all other cases, an array is created. + + The rules aim to create the best fit between a C++ initializer list and + JSON values. The rationale is as follows: + + 1. The empty initializer list is written as `{}` which is exactly an empty + JSON object. + 2. C++ has no way of describing mapped types other than to list a list of + pairs. As JSON requires that keys must be of type string, rule 2 is the + weakest constraint one can pose on initializer lists to interpret them + as an object. + 3. In all other cases, the initializer list could not be interpreted as + JSON object type, so interpreting it as JSON array type is safe. + + With the rules described above, the following JSON values cannot be + expressed by an initializer list: + + - the empty array (`[]`): use @ref array(initializer_list_t) + with an empty initializer list in this case + - arrays whose elements satisfy rule 2: use @ref + array(initializer_list_t) with the same initializer list + in this case + + @note When used without parentheses around an empty initializer list, @ref + basic_json() is called instead of this function, yielding the JSON null + value. + + @param[in] init initializer list with JSON values + + @param[in] type_deduction internal parameter; when set to `true`, the type + of the JSON value is deducted from the initializer list @a init; when set + to `false`, the type provided via @a manual_type is forced. This mode is + used by the functions @ref array(initializer_list_t) and + @ref object(initializer_list_t). + + @param[in] manual_type internal parameter; when @a type_deduction is set + to `false`, the created JSON value will use the provided type (only @ref + value_t::array and @ref value_t::object are valid); when @a type_deduction + is set to `true`, this parameter has no effect + + @throw type_error.301 if @a type_deduction is `false`, @a manual_type is + `value_t::object`, but @a init contains an element which is not a pair + whose first element is a string. In this case, the constructor could not + create an object. If @a type_deduction would have be `true`, an array + would have been created. See @ref object(initializer_list_t) + for an example. + + @complexity Linear in the size of the initializer list @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows how JSON values are created from + initializer lists.,basic_json__list_init_t} + + @sa @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + @sa @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ +basic_json(initializer_list_t init, +bool type_deduction = true, +value_t manual_type = value_t::array) +{ +// check if each element is an array with two elements whose first +// element is a string +bool is_an_object = std::all_of(init.begin(), init.end(), +[](const detail::json_ref& element_ref) +{ +return (element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string()); +}); + +// adjust type if type deduction is not wanted +if (not type_deduction) +{ +// if array is wanted, do not create an object though possible +if (manual_type == value_t::array) +{ +is_an_object = false; +} + +// if object is wanted but impossible, throw an exception +if (JSON_UNLIKELY(manual_type == value_t::object and not is_an_object)) +{ +JSON_THROW(type_error::create(301, "cannot create object from initializer list")); +} +} + +if (is_an_object) +{ +// the initializer list is a list of pairs -> create object +m_type = value_t::object; +m_value = value_t::object; + +std::for_each(init.begin(), init.end(), [this](const detail::json_ref& element_ref) +{ +auto element = element_ref.moved_or_copied(); +m_value.object->emplace( +std::move(*((*element.m_value.array)[0].m_value.string)), +std::move((*element.m_value.array)[1])); +}); +} +else +{ +// the initializer list describes an array -> create array +m_type = value_t::array; +m_value.array = create(init.begin(), init.end()); +} + +assert_invariant(); +} + +/*! + @brief explicitly create an array from an initializer list + + Creates a JSON array value from a given initializer list. That is, given a + list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the + initializer list is empty, the empty array `[]` is created. + + @note This function is only needed to express two edge cases that cannot + be realized with the initializer list constructor (@ref + basic_json(initializer_list_t, bool, value_t)). These cases + are: + 1. creating an array whose elements are all pairs whose first element is a + string -- in this case, the initializer list constructor would create an + object, taking the first elements as keys + 2. creating an empty array -- passing the empty initializer list to the + initializer list constructor yields an empty object + + @param[in] init initializer list with JSON values to create an array from + (optional) + + @return JSON array value + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `array` + function.,array} + + @sa @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ +static basic_json array(initializer_list_t init = {}) +{ +return basic_json(init, false, value_t::array); +} + +/*! + @brief explicitly create an object from an initializer list + + Creates a JSON object value from a given initializer list. The initializer + lists elements must be pairs, and their first elements must be strings. If + the initializer list is empty, the empty object `{}` is created. + + @note This function is only added for symmetry reasons. In contrast to the + related function @ref array(initializer_list_t), there are + no cases which can only be expressed by this function. That is, any + initializer list @a init can also be passed to the initializer list + constructor @ref basic_json(initializer_list_t, bool, value_t). + + @param[in] init initializer list to create an object from (optional) + + @return JSON object value + + @throw type_error.301 if @a init is not a list of pairs whose first + elements are strings. In this case, no object can be created. When such a + value is passed to @ref basic_json(initializer_list_t, bool, value_t), + an array would have been created from the passed initializer list @a init. + See example below. + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `object` + function.,object} + + @sa @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + + @since version 1.0.0 + */ +static basic_json object(initializer_list_t init = {}) +{ +return basic_json(init, false, value_t::object); +} + +/*! + @brief construct an array with count copies of given value + + Constructs a JSON array value by creating @a cnt copies of a passed value. + In case @a cnt is `0`, an empty array is created. + + @param[in] cnt the number of JSON copies of @a val to create + @param[in] val the JSON value to copy + + @post `std::distance(begin(),end()) == cnt` holds. + + @complexity Linear in @a cnt. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows examples for the @ref + basic_json(size_type\, const basic_json&) + constructor.,basic_json__size_type_basic_json} + + @since version 1.0.0 + */ +basic_json(size_type cnt, const basic_json& val) +: m_type(value_t::array) +{ +m_value.array = create(cnt, val); +assert_invariant(); +} + +/*! + @brief construct a JSON container given an iterator range + + Constructs the JSON value with the contents of the range `[first, last)`. + The semantics depends on the different types a JSON value can have: + - In case of a null type, invalid_iterator.206 is thrown. + - In case of other primitive types (number, boolean, or string), @a first + must be `begin()` and @a last must be `end()`. In this case, the value is + copied. Otherwise, invalid_iterator.204 is thrown. + - In case of structured types (array, object), the constructor behaves as + similar versions for `std::vector` or `std::map`; that is, a JSON array + or object is constructed from the values in the range. + + @tparam InputIT an input iterator type (@ref iterator or @ref + const_iterator) + + @param[in] first begin of the range to copy from (included) + @param[in] last end of the range to copy from (excluded) + + @pre Iterators @a first and @a last must be initialized. **This + precondition is enforced with an assertion (see warning).** If + assertions are switched off, a violation of this precondition yields + undefined behavior. + + @pre Range `[first, last)` is valid. Usually, this precondition cannot be + checked efficiently. Only certain edge cases are detected; see the + description of the exceptions below. A violation of this precondition + yields undefined behavior. + + @warning A precondition is enforced with a runtime assertion that will + result in calling `std::abort` if this precondition is not met. + Assertions can be disabled by defining `NDEBUG` at compile time. + See http://en.cppreference.com/w/cpp/error/assert for more + information. + + @throw invalid_iterator.201 if iterators @a first and @a last are not + compatible (i.e., do not belong to the same JSON value). In this case, + the range `[first, last)` is undefined. + @throw invalid_iterator.204 if iterators @a first and @a last belong to a + primitive type (number, boolean, or string), but @a first does not point + to the first element any more. In this case, the range `[first, last)` is + undefined. See example code below. + @throw invalid_iterator.206 if iterators @a first and @a last belong to a + null value. In this case, the range `[first, last)` is undefined. + + @complexity Linear in distance between @a first and @a last. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows several ways to create JSON values by + specifying a subrange with iterators.,basic_json__InputIt_InputIt} + + @since version 1.0.0 + */ +template::value or +std::is_same::value, int>::type = 0> +basic_json(InputIT first, InputIT last) +{ +assert(first.m_object != nullptr); +assert(last.m_object != nullptr); + +// make sure iterator fits the current value +if (JSON_UNLIKELY(first.m_object != last.m_object)) +{ +JSON_THROW(invalid_iterator::create(201, "iterators are not compatible")); +} + +// copy type from first iterator +m_type = first.m_object->m_type; + +// check if iterator range is complete for primitive values +switch (m_type) +{ +case value_t::boolean: +case value_t::number_float: +case value_t::number_integer: +case value_t::number_unsigned: +case value_t::string: +{ +if (JSON_UNLIKELY(not first.m_it.primitive_iterator.is_begin() +or not last.m_it.primitive_iterator.is_end())) +{ +JSON_THROW(invalid_iterator::create(204, "iterators out of range")); +} +break; +} + +default: +break; +} + +switch (m_type) +{ +case value_t::number_integer: +{ +m_value.number_integer = first.m_object->m_value.number_integer; +break; +} + +case value_t::number_unsigned: +{ +m_value.number_unsigned = first.m_object->m_value.number_unsigned; +break; +} + +case value_t::number_float: +{ +m_value.number_float = first.m_object->m_value.number_float; +break; +} + +case value_t::boolean: +{ +m_value.boolean = first.m_object->m_value.boolean; +break; +} + +case value_t::string: +{ +m_value = *first.m_object->m_value.string; +break; +} + +case value_t::object: +{ +m_value.object = create(first.m_it.object_iterator, +last.m_it.object_iterator); +break; +} + +case value_t::array: +{ +m_value.array = create(first.m_it.array_iterator, +last.m_it.array_iterator); +break; +} + +default: +JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + +std::string(first.m_object->type_name()))); +} + +assert_invariant(); +} + + +/////////////////////////////////////// +// other constructors and destructor // +/////////////////////////////////////// + +/// @private +basic_json(const detail::json_ref& ref) +: basic_json(ref.moved_or_copied()) +{} + +/*! + @brief copy constructor + + Creates a copy of a given JSON value. + + @param[in] other the JSON value to copy + + @post `*this == other` + + @complexity Linear in the size of @a other. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - As postcondition, it holds: `other == basic_json(other)`. + + @liveexample{The following code shows an example for the copy + constructor.,basic_json__basic_json} + + @since version 1.0.0 + */ +basic_json(const basic_json& other) +: m_type(other.m_type) +{ +// check of passed value is valid +other.assert_invariant(); + +switch (m_type) +{ +case value_t::object: +{ +m_value = *other.m_value.object; +break; +} + +case value_t::array: +{ +m_value = *other.m_value.array; +break; +} + +case value_t::string: +{ +m_value = *other.m_value.string; +break; +} + +case value_t::boolean: +{ +m_value = other.m_value.boolean; +break; +} + +case value_t::number_integer: +{ +m_value = other.m_value.number_integer; +break; +} + +case value_t::number_unsigned: +{ +m_value = other.m_value.number_unsigned; +break; +} + +case value_t::number_float: +{ +m_value = other.m_value.number_float; +break; +} + +default: +break; +} + +assert_invariant(); +} + +/*! + @brief move constructor + + Move constructor. Constructs a JSON value with the contents of the given + value @a other using move semantics. It "steals" the resources from @a + other and leaves it as JSON null value. + + @param[in,out] other value to move to this object + + @post `*this` has the same value as @a other before the call. + @post @a other is a JSON null value. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @requirement This function helps `basic_json` satisfying the + [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible) + requirements. + + @liveexample{The code below shows the move constructor explicitly called + via std::move.,basic_json__moveconstructor} + + @since version 1.0.0 + */ +basic_json(basic_json&& other) noexcept +: m_type(std::move(other.m_type)), +m_value(std::move(other.m_value)) +{ +// check that passed value is valid +other.assert_invariant(); + +// invalidate payload +other.m_type = value_t::null; +other.m_value = {}; + +assert_invariant(); +} + +/*! + @brief copy assignment + + Copy assignment operator. Copies a JSON value via the "copy and swap" + strategy: It is expressed in terms of the copy constructor, destructor, + and the `swap()` member function. + + @param[in] other value to copy from + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + + @liveexample{The code below shows and example for the copy assignment. It + creates a copy of value `a` which is then swapped with `b`. Finally\, the + copy of `a` (which is the null value after the swap) is + destroyed.,basic_json__copyassignment} + + @since version 1.0.0 + */ +reference& operator=(basic_json other) noexcept ( +std::is_nothrow_move_constructible::value and +std::is_nothrow_move_assignable::value and +std::is_nothrow_move_constructible::value and +std::is_nothrow_move_assignable::value +) +{ +// check that passed value is valid +other.assert_invariant(); + +using std::swap; +swap(m_type, other.m_type); +swap(m_value, other.m_value); + +assert_invariant(); +return *this; +} + +/*! + @brief destructor + + Destroys the JSON value and frees all allocated memory. + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - All stored elements are destroyed and all memory is freed. + + @since version 1.0.0 + */ +~basic_json() noexcept +{ +assert_invariant(); +m_value.destroy(m_type); +} + +/// @} + +public: +/////////////////////// +// object inspection // +/////////////////////// + +/// @name object inspection +/// Functions to inspect the type of a JSON value. +/// @{ + +/*! + @brief serialization + + Serialization function for JSON values. The function tries to mimic + Python's `json.dumps()` function, and currently supports its @a indent + and @a ensure_ascii parameters. + + @param[in] indent If indent is nonnegative, then array elements and object + members will be pretty-printed with that indent level. An indent level of + `0` will only insert newlines. `-1` (the default) selects the most compact + representation. + @param[in] indent_char The character to use for indentation if @a indent is + greater than `0`. The default is ` ` (space). + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. + + @return string containing the serialization of the JSON value + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded + + @complexity Linear. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @liveexample{The following example shows the effect of different @a indent\, + @a indent_char\, and @a ensure_ascii parameters to the result of the + serialization.,dump} + + @see https://docs.python.org/2/library/json.html#json.dump + + @since version 1.0.0; indentation character @a indent_char, option + @a ensure_ascii and exceptions added in version 3.0.0 + */ +string_t dump(const int indent = -1, const char indent_char = ' ', +const bool ensure_ascii = false) const +{ +string_t result; +serializer s(detail::output_adapter(result), indent_char); + +if (indent >= 0) +{ +s.dump(*this, true, ensure_ascii, static_cast(indent)); +} +else +{ +s.dump(*this, false, ensure_ascii, 0); +} + +return result; +} + +/*! + @brief return the type of the JSON value (explicit) + + Return the type of the JSON value as a value from the @ref value_t + enumeration. + + @return the type of the JSON value + Value type | return value + ------------------------- | ------------------------- + null | value_t::null + boolean | value_t::boolean + string | value_t::string + number (integer) | value_t::number_integer + number (unsigned integer) | value_t::number_unsigned + number (floating-point) | value_t::number_float + object | value_t::object + array | value_t::array + discarded | value_t::discarded + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `type()` for all JSON + types.,type} + + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + @sa @ref type_name() -- return the type as string + + @since version 1.0.0 + */ +constexpr value_t type() const noexcept +{ +return m_type; +} + +/*! + @brief return whether type is primitive + + This function returns true if and only if the JSON type is primitive + (string, number, boolean, or null). + + @return `true` if type is primitive (string, number, boolean, or null), + `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_primitive()` for all JSON + types.,is_primitive} + + @sa @ref is_structured() -- returns whether JSON value is structured + @sa @ref is_null() -- returns whether JSON value is `null` + @sa @ref is_string() -- returns whether JSON value is a string + @sa @ref is_boolean() -- returns whether JSON value is a boolean + @sa @ref is_number() -- returns whether JSON value is a number + + @since version 1.0.0 + */ +constexpr bool is_primitive() const noexcept +{ +return is_null() or is_string() or is_boolean() or is_number(); +} + +/*! + @brief return whether type is structured + + This function returns true if and only if the JSON type is structured + (array or object). + + @return `true` if type is structured (array or object), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_structured()` for all JSON + types.,is_structured} + + @sa @ref is_primitive() -- returns whether value is primitive + @sa @ref is_array() -- returns whether value is an array + @sa @ref is_object() -- returns whether value is an object + + @since version 1.0.0 + */ +constexpr bool is_structured() const noexcept +{ +return is_array() or is_object(); +} + +/*! + @brief return whether value is null + + This function returns true if and only if the JSON value is null. + + @return `true` if type is null, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_null()` for all JSON + types.,is_null} + + @since version 1.0.0 + */ +constexpr bool is_null() const noexcept +{ +return (m_type == value_t::null); +} + +/*! + @brief return whether value is a boolean + + This function returns true if and only if the JSON value is a boolean. + + @return `true` if type is boolean, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_boolean()` for all JSON + types.,is_boolean} + + @since version 1.0.0 + */ +constexpr bool is_boolean() const noexcept +{ +return (m_type == value_t::boolean); +} + +/*! + @brief return whether value is a number + + This function returns true if and only if the JSON value is a number. This + includes both integer (signed and unsigned) and floating-point values. + + @return `true` if type is number (regardless whether integer, unsigned + integer or floating-type), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number()` for all JSON + types.,is_number} + + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ +constexpr bool is_number() const noexcept +{ +return is_number_integer() or is_number_float(); +} + +/*! + @brief return whether value is an integer number + + This function returns true if and only if the JSON value is a signed or + unsigned integer number. This excludes floating-point values. + + @return `true` if type is an integer or unsigned integer number, `false` + otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_integer()` for all + JSON types.,is_number_integer} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ +constexpr bool is_number_integer() const noexcept +{ +return (m_type == value_t::number_integer or m_type == value_t::number_unsigned); +} + +/*! + @brief return whether value is an unsigned integer number + + This function returns true if and only if the JSON value is an unsigned + integer number. This excludes floating-point and signed integer values. + + @return `true` if type is an unsigned integer number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_unsigned()` for all + JSON types.,is_number_unsigned} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 2.0.0 + */ +constexpr bool is_number_unsigned() const noexcept +{ +return (m_type == value_t::number_unsigned); +} + +/*! + @brief return whether value is a floating-point number + + This function returns true if and only if the JSON value is a + floating-point number. This excludes signed and unsigned integer values. + + @return `true` if type is a floating-point number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_float()` for all + JSON types.,is_number_float} + + @sa @ref is_number() -- check if value is number + @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + + @since version 1.0.0 + */ +constexpr bool is_number_float() const noexcept +{ +return (m_type == value_t::number_float); +} + +/*! + @brief return whether value is an object + + This function returns true if and only if the JSON value is an object. + + @return `true` if type is object, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_object()` for all JSON + types.,is_object} + + @since version 1.0.0 + */ +constexpr bool is_object() const noexcept +{ +return (m_type == value_t::object); +} + +/*! + @brief return whether value is an array + + This function returns true if and only if the JSON value is an array. + + @return `true` if type is array, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_array()` for all JSON + types.,is_array} + + @since version 1.0.0 + */ +constexpr bool is_array() const noexcept +{ +return (m_type == value_t::array); +} + +/*! + @brief return whether value is a string + + This function returns true if and only if the JSON value is a string. + + @return `true` if type is string, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_string()` for all JSON + types.,is_string} + + @since version 1.0.0 + */ +constexpr bool is_string() const noexcept +{ +return (m_type == value_t::string); +} + +/*! + @brief return whether value is discarded + + This function returns true if and only if the JSON value was discarded + during parsing with a callback function (see @ref parser_callback_t). + + @note This function will always be `false` for JSON values after parsing. + That is, discarded values can only occur during parsing, but will be + removed when inside a structured value or replaced by null in other cases. + + @return `true` if type is discarded, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_discarded()` for all JSON + types.,is_discarded} + + @since version 1.0.0 + */ +constexpr bool is_discarded() const noexcept +{ +return (m_type == value_t::discarded); +} + +/*! + @brief return the type of the JSON value (implicit) + + Implicitly return the type of the JSON value as a value from the @ref + value_t enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies the @ref value_t operator for + all JSON types.,operator__value_t} + + @sa @ref type() -- return the type of the JSON value (explicit) + @sa @ref type_name() -- return the type as string + + @since version 1.0.0 + */ +constexpr operator value_t() const noexcept +{ +return m_type; +} + +/// @} + +private: +////////////////// +// value access // +////////////////// + +/// get a boolean (explicit) +boolean_t get_impl(boolean_t* /*unused*/) const +{ +if (JSON_LIKELY(is_boolean())) +{ +return m_value.boolean; +} + +JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name()))); +} + +/// get a pointer to the value (object) +object_t* get_impl_ptr(object_t* /*unused*/) noexcept +{ +return is_object() ? m_value.object : nullptr; +} + +/// get a pointer to the value (object) +constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept +{ +return is_object() ? m_value.object : nullptr; +} + +/// get a pointer to the value (array) +array_t* get_impl_ptr(array_t* /*unused*/) noexcept +{ +return is_array() ? m_value.array : nullptr; +} + +/// get a pointer to the value (array) +constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept +{ +return is_array() ? m_value.array : nullptr; +} + +/// get a pointer to the value (string) +string_t* get_impl_ptr(string_t* /*unused*/) noexcept +{ +return is_string() ? m_value.string : nullptr; +} + +/// get a pointer to the value (string) +constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept +{ +return is_string() ? m_value.string : nullptr; +} + +/// get a pointer to the value (boolean) +boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept +{ +return is_boolean() ? &m_value.boolean : nullptr; +} + +/// get a pointer to the value (boolean) +constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept +{ +return is_boolean() ? &m_value.boolean : nullptr; +} + +/// get a pointer to the value (integer number) +number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept +{ +return is_number_integer() ? &m_value.number_integer : nullptr; +} + +/// get a pointer to the value (integer number) +constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept +{ +return is_number_integer() ? &m_value.number_integer : nullptr; +} + +/// get a pointer to the value (unsigned number) +number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept +{ +return is_number_unsigned() ? &m_value.number_unsigned : nullptr; +} + +/// get a pointer to the value (unsigned number) +constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept +{ +return is_number_unsigned() ? &m_value.number_unsigned : nullptr; +} + +/// get a pointer to the value (floating-point number) +number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept +{ +return is_number_float() ? &m_value.number_float : nullptr; +} + +/// get a pointer to the value (floating-point number) +constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept +{ +return is_number_float() ? &m_value.number_float : nullptr; +} + +/*! + @brief helper function to implement get_ref() + + This function helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw type_error.303 if ReferenceType does not match underlying value + type of the current JSON + */ +template +static ReferenceType get_ref_impl(ThisType& obj) +{ +// delegate the call to get_ptr<>() +auto ptr = obj.template get_ptr::type>(); + +if (JSON_LIKELY(ptr != nullptr)) +{ +return *ptr; +} + +JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name()))); +} + +public: +/// @name value access +/// Direct access to the stored value of a JSON value. +/// @{ + +/*! + @brief get special-case overload + + This overloads avoids a lot of template boilerplate, it can be seen as the + identity method + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this + + @complexity Constant. + + @since version 2.1.0 + */ +template::type, basic_json_t>::value, +int> = 0> +basic_json get() const +{ +return *this; +} + +/*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value + which is [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) + and [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and + - @ref json_serializer does not have a `from_json()` method of + the form `ValueType from_json(const basic_json&)` + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get__ValueType_const} + + @since version 2.1.0 + */ +template, +detail::enable_if_t < +not std::is_same::value and +detail::has_from_json::value and +not detail::has_non_default_from_json::value, +int> = 0> +ValueType get() const noexcept(noexcept( +JSONSerializer::from_json(std::declval(), std::declval()))) +{ +// we cannot static_assert on ValueTypeCV being non-const, because +// there is support for get(), which is why we +// still need the uncvref +static_assert(not std::is_reference::value, +"get() cannot be used with reference types, you might want to use get_ref()"); +static_assert(std::is_default_constructible::value, +"types must be DefaultConstructible when used with get()"); + +ValueType ret; +JSONSerializer::from_json(*this, ret); +return ret; +} + +/*! + @brief get a value (explicit); special case + + Explicit type conversion between the JSON value and a compatible value + which is **not** [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) + and **not** [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + return JSONSerializer::from_json(*this); + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json and + - @ref json_serializer has a `from_json()` method of the form + `ValueType from_json(const basic_json&)` + + @note If @ref json_serializer has both overloads of + `from_json()`, this one is chosen. + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @since version 2.1.0 + */ +template, +detail::enable_if_t::value and +detail::has_non_default_from_json::value, +int> = 0> +ValueType get() const noexcept(noexcept( +JSONSerializer::from_json(std::declval()))) +{ +static_assert(not std::is_reference::value, +"get() cannot be used with reference types, you might want to use get_ref()"); +return JSONSerializer::from_json(*this); +} + +/*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ +template::value, int>::type = 0> +PointerType get() noexcept +{ +// delegate the call to get_ptr +return get_ptr(); +} + +/*! + @brief get a pointer value (explicit) + @copydoc get() + */ +template::value, int>::type = 0> +constexpr const PointerType get() const noexcept +{ +// delegate the call to get_ptr +return get_ptr(); +} + +/*! + @brief get a pointer value (implicit) + + Implicit pointer access to the internally stored JSON value. No copies are + made. + + @warning Writing data to the pointee of the result yields an undefined + state. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. Enforced by a static + assertion. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get_ptr} + + @since version 1.0.0 + */ +template::value, int>::type = 0> +PointerType get_ptr() noexcept +{ +// get the type of the PointerType (remove pointer and const) +using pointee_t = typename std::remove_const::type>::type>::type; +// make sure the type matches the allowed types +static_assert( +std::is_same::value +or std::is_same::value +or std::is_same::value +or std::is_same::value +or std::is_same::value +or std::is_same::value +or std::is_same::value +, "incompatible pointer type"); + +// delegate the call to get_impl_ptr<>() +return get_impl_ptr(static_cast(nullptr)); +} + +/*! + @brief get a pointer value (implicit) + @copydoc get_ptr() + */ +template::value and +std::is_const::type>::value, int>::type = 0> +constexpr const PointerType get_ptr() const noexcept +{ +// get the type of the PointerType (remove pointer and const) +using pointee_t = typename std::remove_const::type>::type>::type; +// make sure the type matches the allowed types +static_assert( +std::is_same::value +or std::is_same::value +or std::is_same::value +or std::is_same::value +or std::is_same::value +or std::is_same::value +or std::is_same::value +, "incompatible pointer type"); + +// delegate the call to get_impl_ptr<>() const +return get_impl_ptr(static_cast(nullptr)); +} + +/*! + @brief get a reference value (implicit) + + Implicit reference access to the internally stored JSON value. No copies + are made. + + @warning Writing data to the referee of the result yields an undefined + state. + + @tparam ReferenceType reference type; must be a reference to @ref array_t, + @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or + @ref number_float_t. Enforced by static assertion. + + @return reference to the internally stored JSON value if the requested + reference type @a ReferenceType fits to the JSON value; throws + type_error.303 otherwise + + @throw type_error.303 in case passed type @a ReferenceType is incompatible + with the stored JSON value; see example below + + @complexity Constant. + + @liveexample{The example shows several calls to `get_ref()`.,get_ref} + + @since version 1.1.0 + */ +template::value, int>::type = 0> +ReferenceType get_ref() +{ +// delegate call to get_ref_impl +return get_ref_impl(*this); +} + +/*! + @brief get a reference value (implicit) + @copydoc get_ref() + */ +template::value and +std::is_const::type>::value, int>::type = 0> +ReferenceType get_ref() const +{ +// delegate call to get_ref_impl +return get_ref_impl(*this); +} + +/*! + @brief get a value (implicit) + + Implicit type conversion between the JSON value and a compatible value. + The call is realized by calling @ref get() const. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays. The character type of @ref string_t + as well as an initializer list of this type is excluded to avoid + ambiguities as these types implicitly convert to `std::string`. + + @return copy of the JSON value, converted to type @a ValueType + + @throw type_error.302 in case passed type @a ValueType is incompatible + to the JSON value type (e.g., the JSON value is of type boolean, but a + string is requested); see example below + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0.0 + */ +template < typename ValueType, typename std::enable_if < +not std::is_pointer::value and +not std::is_same>::value and +not std::is_same::value +#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 +and not std::is_same>::value +#endif +#if defined(JSON_HAS_CPP_17) +and not std::is_same::value +#endif +, int >::type = 0 > +operator ValueType() const +{ +// delegate the call to get<>() const +return get(); +} + +/// @} + + +//////////////////// +// element access // +//////////////////// + +/// @name element access +/// Access to the JSON value. +/// @{ + +/*! + @brief access specified array element with bounds checking + + Returns a reference to the element at specified location @a idx, with + bounds checking. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__size_type} + */ +reference at(size_type idx) +{ +// at only works for arrays +if (JSON_LIKELY(is_array())) +{ +JSON_TRY +{ +return m_value.array->at(idx); +} +JSON_CATCH (std::out_of_range&) +{ +// create better exception explanation +JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); +} +} +else +{ +JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); +} +} + +/*! + @brief access specified array element with bounds checking + + Returns a const reference to the element at specified location @a idx, + with bounds checking. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__size_type_const} + */ +const_reference at(size_type idx) const +{ +// at only works for arrays +if (JSON_LIKELY(is_array())) +{ +JSON_TRY +{ +return m_value.array->at(idx); +} +JSON_CATCH (std::out_of_range&) +{ +// create better exception explanation +JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); +} +} +else +{ +JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); +} +} + +/*! + @brief access specified object element with bounds checking + + Returns a reference to the element at with specified key @a key, with + bounds checking. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__object_t_key_type} + */ +reference at(const typename object_t::key_type& key) +{ +// at only works for objects +if (JSON_LIKELY(is_object())) +{ +JSON_TRY +{ +return m_value.object->at(key); +} +JSON_CATCH (std::out_of_range&) +{ +// create better exception explanation +JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); +} +} +else +{ +JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); +} +} + +/*! + @brief access specified object element with bounds checking + + Returns a const reference to the element at with specified key @a key, + with bounds checking. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__object_t_key_type_const} + */ +const_reference at(const typename object_t::key_type& key) const +{ +// at only works for objects +if (JSON_LIKELY(is_object())) +{ +JSON_TRY +{ +return m_value.object->at(key); +} +JSON_CATCH (std::out_of_range&) +{ +// create better exception explanation +JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); +} +} +else +{ +JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); +} +} + +/*! + @brief access specified array element + + Returns a reference to the element at specified location @a idx. + + @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), + then the array is silently filled up with `null` values to make `idx` a + valid reference to the last stored element. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array or null; in that + cases, using the [] operator with an index makes no sense. + + @complexity Constant if @a idx is in the range of the array. Otherwise + linear in `idx - size()`. + + @liveexample{The example below shows how array elements can be read and + written using `[]` operator. Note the addition of `null` + values.,operatorarray__size_type} + + @since version 1.0.0 + */ +reference operator[](size_type idx) +{ +// implicitly convert null value to an empty array +if (is_null()) +{ +m_type = value_t::array; +m_value.array = create(); +assert_invariant(); +} + +// operator[] only works for arrays +if (JSON_LIKELY(is_array())) +{ +// fill up array with null values if given idx is outside range +if (idx >= m_value.array->size()) +{ +m_value.array->insert(m_value.array->end(), +idx - m_value.array->size() + 1, +basic_json()); +} + +return m_value.array->operator[](idx); +} + +JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); +} + +/*! + @brief access specified array element + + Returns a const reference to the element at specified location @a idx. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array; in that case, + using the [] operator with an index makes no sense. + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + the `[]` operator.,operatorarray__size_type_const} + + @since version 1.0.0 + */ +const_reference operator[](size_type idx) const +{ +// const operator[] only works for arrays +if (JSON_LIKELY(is_array())) +{ +return m_value.array->operator[](idx); +} + +JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); +} + +/*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ +reference operator[](const typename object_t::key_type& key) +{ +// implicitly convert null value to an empty object +if (is_null()) +{ +m_type = value_t::object; +m_value.object = create(); +assert_invariant(); +} + +// operator[] only works for objects +if (JSON_LIKELY(is_object())) +{ +return m_value.object->operator[](key); +} + +JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); +} + +/*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ +const_reference operator[](const typename object_t::key_type& key) const +{ +// const operator[] only works for objects +if (JSON_LIKELY(is_object())) +{ +assert(m_value.object->find(key) != m_value.object->end()); +return m_value.object->find(key)->second; +} + +JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); +} + +/*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ +template +reference operator[](T* key) +{ +// implicitly convert null to object +if (is_null()) +{ +m_type = value_t::object; +m_value = value_t::object; +assert_invariant(); +} + +// at only works for objects +if (JSON_LIKELY(is_object())) +{ +return m_value.object->operator[](key); +} + +JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); +} + +/*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ +template +const_reference operator[](T* key) const +{ +// at only works for objects +if (JSON_LIKELY(is_object())) +{ +assert(m_value.object->find(key) != m_value.object->end()); +return m_value.object->find(key)->second; +} + +JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); +} + +/*! + @brief access specified object element with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(key); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const typename object_t::key_type&), this function + does not throw if the given key @a key was not found. + + @note Unlike @ref operator[](const typename object_t::key_type& key), this + function does not implicitly add an element to the position defined by @a + key. This function is furthermore also applicable to const objects. + + @param[in] key key of the element to access + @param[in] default_value the value to return if @a key is not found + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.306 if the JSON value is not an object; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + + @since version 1.0.0 + */ +template::value, int>::type = 0> +ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const +{ +// at only works for objects +if (JSON_LIKELY(is_object())) +{ +// if key is found, return value and given default value otherwise +const auto it = find(key); +if (it != end()) +{ +return *it; +} + +return default_value; +} + +JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); +} + +/*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const + */ +string_t value(const typename object_t::key_type& key, const char* default_value) const +{ +return value(key, string_t(default_value)); +} + +/*! + @brief access specified object element via JSON Pointer with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(ptr); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const json_pointer&), this function does not throw + if the given key @a key was not found. + + @param[in] ptr a JSON pointer to the element to access + @param[in] default_value the value to return if @a ptr found no value + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.306 if the JSON value is not an objec; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value_ptr} + + @sa @ref operator[](const json_pointer&) for unchecked access by reference + + @since version 2.0.2 + */ +template::value, int>::type = 0> +ValueType value(const json_pointer& ptr, const ValueType& default_value) const +{ +// at only works for objects +if (JSON_LIKELY(is_object())) +{ +// if pointer resolves a value, return it or use default value +JSON_TRY +{ +return ptr.get_checked(this); +} +JSON_CATCH (out_of_range&) +{ +return default_value; +} +} + +JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); +} + +/*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const json_pointer&, ValueType) const + */ +string_t value(const json_pointer& ptr, const char* default_value) const +{ +return value(ptr, string_t(default_value)); +} + +/*! + @brief access the first element + + Returns a reference to the first element in the container. For a JSON + container `c`, the expression `c.front()` is equivalent to `*c.begin()`. + + @return In case of a structured type (array or object), a reference to the + first element is returned. In case of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on `null` value + + @liveexample{The following code shows an example for `front()`.,front} + + @sa @ref back() -- access the last element + + @since version 1.0.0 + */ +reference front() +{ +return *begin(); +} + +/*! + @copydoc basic_json::front() + */ +const_reference front() const +{ +return *cbegin(); +} + +/*! + @brief access the last element + + Returns a reference to the last element in the container. For a JSON + container `c`, the expression `c.back()` is equivalent to + @code {.cpp} + auto tmp = c.end(); + --tmp; + return *tmp; + @endcode + + @return In case of a structured type (array or object), a reference to the + last element is returned. In case of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on a `null` value. See example + below. + + @liveexample{The following code shows an example for `back()`.,back} + + @sa @ref front() -- access the first element + + @since version 1.0.0 + */ +reference back() +{ +auto tmp = end(); +--tmp; +return *tmp; +} + +/*! + @copydoc basic_json::back() + */ +const_reference back() const +{ +auto tmp = cend(); +--tmp; +return *tmp; +} + +/*! + @brief remove element given an iterator + + Removes the element specified by iterator @a pos. The iterator @a pos must + be valid and dereferenceable. Thus the `end()` iterator (which is valid, + but is not dereferenceable) cannot be used as a value for @a pos. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] pos iterator to the element to remove + @return Iterator following the last removed element. If the iterator @a + pos refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.202 if called on an iterator which does not belong + to the current JSON value; example: `"iterator does not fit current + value"` + @throw invalid_iterator.205 if called on a primitive type with invalid + iterator (i.e., any iterator which is not `begin()`); example: `"iterator + out of range"` + + @complexity The complexity depends on the type: + - objects: amortized constant + - arrays: linear in distance between @a pos and the end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType} + + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ +template::value or +std::is_same::value, int>::type += 0> +IteratorType erase(IteratorType pos) +{ +// make sure iterator fits the current value +if (JSON_UNLIKELY(this != pos.m_object)) +{ +JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); +} + +IteratorType result = end(); + +switch (m_type) +{ +case value_t::boolean: +case value_t::number_float: +case value_t::number_integer: +case value_t::number_unsigned: +case value_t::string: +{ +if (JSON_UNLIKELY(not pos.m_it.primitive_iterator.is_begin())) +{ +JSON_THROW(invalid_iterator::create(205, "iterator out of range")); +} + +if (is_string()) +{ +AllocatorType alloc; +std::allocator_traits::destroy(alloc, m_value.string); +std::allocator_traits::deallocate(alloc, m_value.string, 1); +m_value.string = nullptr; +} + +m_type = value_t::null; +assert_invariant(); +break; +} + +case value_t::object: +{ +result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); +break; +} + +case value_t::array: +{ +result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); +break; +} + +default: +JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); +} + +return result; +} + +/*! + @brief remove elements given an iterator range + + Removes the element specified by the range `[first; last)`. The iterator + @a first does not need to be dereferenceable if `first == last`: erasing + an empty range is a no-op. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] first iterator to the beginning of the range to remove + @param[in] last iterator past the end of the range to remove + @return Iterator following the last removed element. If the iterator @a + second refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.203 if called on iterators which does not belong + to the current JSON value; example: `"iterators do not fit current value"` + @throw invalid_iterator.204 if called on a primitive type with invalid + iterators (i.e., if `first != begin()` and `last != end()`); example: + `"iterators out of range"` + + @complexity The complexity depends on the type: + - objects: `log(size()) + std::distance(first, last)` + - arrays: linear in the distance between @a first and @a last, plus linear + in the distance between @a last and end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType_IteratorType} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ +template::value or +std::is_same::value, int>::type += 0> +IteratorType erase(IteratorType first, IteratorType last) +{ +// make sure iterator fits the current value +if (JSON_UNLIKELY(this != first.m_object or this != last.m_object)) +{ +JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value")); +} + +IteratorType result = end(); + +switch (m_type) +{ +case value_t::boolean: +case value_t::number_float: +case value_t::number_integer: +case value_t::number_unsigned: +case value_t::string: +{ +if (JSON_LIKELY(not first.m_it.primitive_iterator.is_begin() +or not last.m_it.primitive_iterator.is_end())) +{ +JSON_THROW(invalid_iterator::create(204, "iterators out of range")); +} + +if (is_string()) +{ +AllocatorType alloc; +std::allocator_traits::destroy(alloc, m_value.string); +std::allocator_traits::deallocate(alloc, m_value.string, 1); +m_value.string = nullptr; +} + +m_type = value_t::null; +assert_invariant(); +break; +} + +case value_t::object: +{ +result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, +last.m_it.object_iterator); +break; +} + +case value_t::array: +{ +result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, +last.m_it.array_iterator); +break; +} + +default: +JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); +} + +return result; +} + +/*! + @brief remove element from a JSON object given a key + + Removes elements from a JSON object with the key value @a key. + + @param[in] key value of the elements to remove + + @return Number of elements removed. If @a ObjectType is the default + `std::map` type, the return value will always be `0` (@a key was not + found) or `1` (@a key was found). + + @post References and iterators to the erased elements are invalidated. + Other references and iterators are not affected. + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + + @complexity `log(size()) + count(key)` + + @liveexample{The example shows the effect of `erase()`.,erase__key_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ +size_type erase(const typename object_t::key_type& key) +{ +// this erase only works for objects +if (JSON_LIKELY(is_object())) +{ +return m_value.object->erase(key); +} + +JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); +} + +/*! + @brief remove element from a JSON array given an index + + Removes element from a JSON array at the index @a idx. + + @param[in] idx index of the element to remove + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + @throw out_of_range.401 when `idx >= size()`; example: `"array index 17 + is out of range"` + + @complexity Linear in distance between @a idx and the end of the container. + + @liveexample{The example shows the effect of `erase()`.,erase__size_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + + @since version 1.0.0 + */ +void erase(const size_type idx) +{ +// this erase only works for arrays +if (JSON_LIKELY(is_array())) +{ +if (JSON_UNLIKELY(idx >= size())) +{ +JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); +} + +m_value.array->erase(m_value.array->begin() + static_cast(idx)); +} +else +{ +JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); +} +} + +/// @} + + +//////////// +// lookup // +//////////// + +/// @name lookup +/// @{ + +/*! + @brief find an element in a JSON object + + Finds an element in a JSON object with key equivalent to @a key. If the + element is not found or the JSON value is not an object, end() is + returned. + + @note This method always returns @ref end() when executed on a JSON type + that is not an object. + + @param[in] key key value of the element to search for. + + @return Iterator to an element with key equivalent to @a key. If no such + element is found or the JSON value is not an object, past-the-end (see + @ref end()) iterator is returned. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `find()` is used.,find__key_type} + + @since version 1.0.0 + */ +template +iterator find(KeyT&& key) +{ +auto result = end(); + +if (is_object()) +{ +result.m_it.object_iterator = m_value.object->find(std::forward(key)); +} + +return result; +} + +/*! + @brief find an element in a JSON object + @copydoc find(KeyT&&) + */ +template +const_iterator find(KeyT&& key) const +{ +auto result = cend(); + +if (is_object()) +{ +result.m_it.object_iterator = m_value.object->find(std::forward(key)); +} + +return result; +} + +/*! + @brief returns the number of occurrences of a key in a JSON object + + Returns the number of elements with key @a key. If ObjectType is the + default `std::map` type, the return value will always be `0` (@a key was + not found) or `1` (@a key was found). + + @note This method always returns `0` when executed on a JSON type that is + not an object. + + @param[in] key key value of the element to count + + @return Number of elements with key @a key. If the JSON value is not an + object, the return value will be `0`. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `count()` is used.,count} + + @since version 1.0.0 + */ +template +size_type count(KeyT&& key) const +{ +// return 0 for all nonobject types +return is_object() ? m_value.object->count(std::forward(key)) : 0; +} + +/// @} + + +/////////////// +// iterators // +/////////////// + +/// @name iterators +/// @{ + +/*! + @brief returns an iterator to the first element + + Returns an iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `begin()`.,begin} + + @sa @ref cbegin() -- returns a const iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ +iterator begin() noexcept +{ +iterator result(this); +result.set_begin(); +return result; +} + +/*! + @copydoc basic_json::cbegin() + */ +const_iterator begin() const noexcept +{ +return cbegin(); +} + +/*! + @brief returns a const iterator to the first element + + Returns a const iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).begin()`. + + @liveexample{The following code shows an example for `cbegin()`.,cbegin} + + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ +const_iterator cbegin() const noexcept +{ +const_iterator result(this); +result.set_begin(); +return result; +} + +/*! + @brief returns an iterator to one past the last element + + Returns an iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `end()`.,end} + + @sa @ref cend() -- returns a const iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ +iterator end() noexcept +{ +iterator result(this); +result.set_end(); +return result; +} + +/*! + @copydoc basic_json::cend() + */ +const_iterator end() const noexcept +{ +return cend(); +} + +/*! + @brief returns a const iterator to one past the last element + + Returns a const iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).end()`. + + @liveexample{The following code shows an example for `cend()`.,cend} + + @sa @ref end() -- returns an iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ +const_iterator cend() const noexcept +{ +const_iterator result(this); +result.set_end(); +return result; +} + +/*! + @brief returns an iterator to the reverse-beginning + + Returns an iterator to the reverse-beginning; that is, the last element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(end())`. + + @liveexample{The following code shows an example for `rbegin()`.,rbegin} + + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ +reverse_iterator rbegin() noexcept +{ +return reverse_iterator(end()); +} + +/*! + @copydoc basic_json::crbegin() + */ +const_reverse_iterator rbegin() const noexcept +{ +return crbegin(); +} + +/*! + @brief returns an iterator to the reverse-end + + Returns an iterator to the reverse-end; that is, one before the first + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(begin())`. + + @liveexample{The following code shows an example for `rend()`.,rend} + + @sa @ref crend() -- returns a const reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ +reverse_iterator rend() noexcept +{ +return reverse_iterator(begin()); +} + +/*! + @copydoc basic_json::crend() + */ +const_reverse_iterator rend() const noexcept +{ +return crend(); +} + +/*! + @brief returns a const reverse iterator to the last element + + Returns a const iterator to the reverse-beginning; that is, the last + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rbegin()`. + + @liveexample{The following code shows an example for `crbegin()`.,crbegin} + + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ +const_reverse_iterator crbegin() const noexcept +{ +return const_reverse_iterator(cend()); +} + +/*! + @brief returns a const reverse iterator to one before the first + + Returns a const reverse iterator to the reverse-end; that is, one before + the first element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rend()`. + + @liveexample{The following code shows an example for `crend()`.,crend} + + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ +const_reverse_iterator crend() const noexcept +{ +return const_reverse_iterator(cbegin()); +} + +public: +/*! + @brief wrapper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without iterator_wrapper: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without iterator proxy: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with iterator proxy: + + @code{cpp} + for (auto it : json::iterator_wrapper(j_object)) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). + + @param[in] ref reference to a JSON value + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the wrapper is used,iterator_wrapper} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @note The name of this function is not yet final and may change in the + future. + + @deprecated This stream operator is deprecated and will be removed in + future 4.0.0 of the library. Please use @ref items() instead; + that is, replace `json::iterator_wrapper(j)` with `j.items()`. + */ +JSON_DEPRECATED +static iteration_proxy iterator_wrapper(reference ref) noexcept +{ +return ref.items(); +} + +/*! + @copydoc iterator_wrapper(reference) + */ +JSON_DEPRECATED +static iteration_proxy iterator_wrapper(const_reference ref) noexcept +{ +return ref.items(); +} + +/*! + @brief helper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without `items()` function: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without `items()` function: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with `items()` function: + + @code{cpp} + for (auto it : j_object.items()) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). For primitive types (e.g., numbers), + `key()` returns an empty string. + + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the function is used.,items} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 3.x.x. + */ +iteration_proxy items() noexcept +{ +return iteration_proxy(*this); +} + +/*! + @copydoc items() + */ +iteration_proxy items() const noexcept +{ +return iteration_proxy(*this); +} + +/// @} + + +////////////// +// capacity // +////////////// + +/// @name capacity +/// @{ + +/*! + @brief checks whether the container is empty. + + Checks if a JSON value has no elements (i.e. whether its @ref size is `0`). + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `true` + boolean | `false` + string | `false` + number | `false` + object | result of function `object_t::empty()` + array | result of function `array_t::empty()` + + @liveexample{The following code uses `empty()` to check if a JSON + object contains any elements.,empty} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `empty()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return whether a string stored as JSON value + is empty - it returns whether the JSON container itself is empty which is + false in the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `begin() == end()`. + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ +bool empty() const noexcept +{ +switch (m_type) +{ +case value_t::null: +{ +// null values are empty +return true; +} + +case value_t::array: +{ +// delegate call to array_t::empty() +return m_value.array->empty(); +} + +case value_t::object: +{ +// delegate call to object_t::empty() +return m_value.object->empty(); +} + +default: +{ +// all other types are nonempty +return false; +} +} +} + +/*! + @brief returns the number of elements + + Returns the number of elements in a JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` + boolean | `1` + string | `1` + number | `1` + object | result of function object_t::size() + array | result of function array_t::size() + + @liveexample{The following code calls `size()` on the different value + types.,size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their size() functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return the length of a string stored as JSON + value - it returns the number of elements in the JSON value which is 1 in + the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `std::distance(begin(), end())`. + + @sa @ref empty() -- checks whether the container is empty + @sa @ref max_size() -- returns the maximal number of elements + + @since version 1.0.0 + */ +size_type size() const noexcept +{ +switch (m_type) +{ +case value_t::null: +{ +// null values are empty +return 0; +} + +case value_t::array: +{ +// delegate call to array_t::size() +return m_value.array->size(); +} + +case value_t::object: +{ +// delegate call to object_t::size() +return m_value.object->size(); +} + +default: +{ +// all other types have size 1 +return 1; +} +} +} + +/*! + @brief returns the maximum possible number of elements + + Returns the maximum number of elements a JSON value is able to hold due to + system or library implementation limitations, i.e. `std::distance(begin(), + end())` for the JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` (same as `size()`) + boolean | `1` (same as `size()`) + string | `1` (same as `size()`) + number | `1` (same as `size()`) + object | result of function `object_t::max_size()` + array | result of function `array_t::max_size()` + + @liveexample{The following code calls `max_size()` on the different value + types. Note the output is implementation specific.,max_size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `max_size()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of returning `b.size()` where `b` is the largest + possible JSON value. + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ +size_type max_size() const noexcept +{ +switch (m_type) +{ +case value_t::array: +{ +// delegate call to array_t::max_size() +return m_value.array->max_size(); +} + +case value_t::object: +{ +// delegate call to object_t::max_size() +return m_value.object->max_size(); +} + +default: +{ +// all other types have max_size() == size() +return size(); +} +} +} + +/// @} + + +/////////////// +// modifiers // +/////////////// + +/// @name modifiers +/// @{ + +/*! + @brief clears the contents + + Clears the content of a JSON value and resets it to the default value as + if @ref basic_json(value_t) would have been called with the current value + type from @ref type(): + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @post Has the same effect as calling + @code {.cpp} + *this = basic_json(type()); + @endcode + + @liveexample{The example below shows the effect of `clear()` to different + JSON types.,clear} + + @complexity Linear in the size of the JSON value. + + @iterators All iterators, pointers and references related to this container + are invalidated. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @sa @ref basic_json(value_t) -- constructor that creates an object with the + same value than calling `clear()` + + @since version 1.0.0 + */ +void clear() noexcept +{ +switch (m_type) +{ +case value_t::number_integer: +{ +m_value.number_integer = 0; +break; +} + +case value_t::number_unsigned: +{ +m_value.number_unsigned = 0; +break; +} + +case value_t::number_float: +{ +m_value.number_float = 0.0; +break; +} + +case value_t::boolean: +{ +m_value.boolean = false; +break; +} + +case value_t::string: +{ +m_value.string->clear(); +break; +} + +case value_t::array: +{ +m_value.array->clear(); +break; +} + +case value_t::object: +{ +m_value.object->clear(); +break; +} + +default: +break; +} +} + +/*! + @brief add an object to an array + + Appends the given element @a val to the end of the JSON value. If the + function is called on a JSON null value, an empty array is created before + appending @a val. + + @param[in] val the value to add to the JSON array + + @throw type_error.308 when called on a type other than JSON array or + null; example: `"cannot use push_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON array. Note how the `null` value was silently + converted to a JSON array.,push_back} + + @since version 1.0.0 + */ +void push_back(basic_json&& val) +{ +// push_back only works for null objects or arrays +if (JSON_UNLIKELY(not(is_null() or is_array()))) +{ +JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); +} + +// transform null object into an array +if (is_null()) +{ +m_type = value_t::array; +m_value = value_t::array; +assert_invariant(); +} + +// add element to array (move semantics) +m_value.array->push_back(std::move(val)); +// invalidate object +val.m_type = value_t::null; +} + +/*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ +reference operator+=(basic_json&& val) +{ +push_back(std::move(val)); +return *this; +} + +/*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ +void push_back(const basic_json& val) +{ +// push_back only works for null objects or arrays +if (JSON_UNLIKELY(not(is_null() or is_array()))) +{ +JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); +} + +// transform null object into an array +if (is_null()) +{ +m_type = value_t::array; +m_value = value_t::array; +assert_invariant(); +} + +// add element to array +m_value.array->push_back(val); +} + +/*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ +reference operator+=(const basic_json& val) +{ +push_back(val); +return *this; +} + +/*! + @brief add an object to an object + + Inserts the given element @a val to the JSON object. If the function is + called on a JSON null value, an empty object is created before inserting + @a val. + + @param[in] val the value to add to the JSON object + + @throw type_error.308 when called on a type other than JSON object or + null; example: `"cannot use push_back() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON object. Note how the `null` value was silently + converted to a JSON object.,push_back__object_t__value} + + @since version 1.0.0 + */ +void push_back(const typename object_t::value_type& val) +{ +// push_back only works for null objects or objects +if (JSON_UNLIKELY(not(is_null() or is_object()))) +{ +JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); +} + +// transform null object into an object +if (is_null()) +{ +m_type = value_t::object; +m_value = value_t::object; +assert_invariant(); +} + +// add element to array +m_value.object->insert(val); +} + +/*! + @brief add an object to an object + @copydoc push_back(const typename object_t::value_type&) + */ +reference operator+=(const typename object_t::value_type& val) +{ +push_back(val); +return *this; +} + +/*! + @brief add an object to an object + + This function allows to use `push_back` with an initializer list. In case + + 1. the current value is an object, + 2. the initializer list @a init contains only two elements, and + 3. the first element of @a init is a string, + + @a init is converted into an object element and added using + @ref push_back(const typename object_t::value_type&). Otherwise, @a init + is converted to a JSON value and added using @ref push_back(basic_json&&). + + @param[in] init an initializer list + + @complexity Linear in the size of the initializer list @a init. + + @note This function is required to resolve an ambiguous overload error, + because pairs like `{"key", "value"}` can be both interpreted as + `object_t::value_type` or `std::initializer_list`, see + https://github.com/nlohmann/json/issues/235 for more information. + + @liveexample{The example shows how initializer lists are treated as + objects when possible.,push_back__initializer_list} + */ +void push_back(initializer_list_t init) +{ +if (is_object() and init.size() == 2 and (*init.begin())->is_string()) +{ +basic_json&& key = init.begin()->moved_or_copied(); +push_back(typename object_t::value_type( +std::move(key.get_ref()), (init.begin() + 1)->moved_or_copied())); +} +else +{ +push_back(basic_json(init)); +} +} + +/*! + @brief add an object to an object + @copydoc push_back(initializer_list_t) + */ +reference operator+=(initializer_list_t init) +{ +push_back(init); +return *this; +} + +/*! + @brief add an object to an array + + Creates a JSON value from the passed parameters @a args to the end of the + JSON value. If the function is called on a JSON null value, an empty array + is created before appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @throw type_error.311 when called on a type other than JSON array or + null; example: `"cannot use emplace_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` can be used to add + elements to a JSON array. Note how the `null` value was silently converted + to a JSON array.,emplace_back} + + @since version 2.0.8 + */ +template +void emplace_back(Args&& ... args) +{ +// emplace_back only works for null objects or arrays +if (JSON_UNLIKELY(not(is_null() or is_array()))) +{ +JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name()))); +} + +// transform null object into an array +if (is_null()) +{ +m_type = value_t::array; +m_value = value_t::array; +assert_invariant(); +} + +// add element to array (perfect forwarding) +m_value.array->emplace_back(std::forward(args)...); +} + +/*! + @brief add an object to an object if key does not exist + + Inserts a new element into a JSON object constructed in-place with the + given @a args if there is no element with the key in the container. If the + function is called on a JSON null value, an empty object is created before + appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @return a pair consisting of an iterator to the inserted element, or the + already-existing element if no insertion happened, and a bool + denoting whether the insertion took place. + + @throw type_error.311 when called on a type other than JSON object or + null; example: `"cannot use emplace() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `emplace()` can be used to add elements + to a JSON object. Note how the `null` value was silently converted to a + JSON object. Further note how no value is added if there was already one + value stored with the same key.,emplace} + + @since version 2.0.8 + */ +template +std::pair emplace(Args&& ... args) +{ +// emplace only works for null objects or arrays +if (JSON_UNLIKELY(not(is_null() or is_object()))) +{ +JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name()))); +} + +// transform null object into an object +if (is_null()) +{ +m_type = value_t::object; +m_value = value_t::object; +assert_invariant(); +} + +// add element to array (perfect forwarding) +auto res = m_value.object->emplace(std::forward(args)...); +// create result iterator and set iterator to the result of emplace +auto it = begin(); +it.m_it.object_iterator = res.first; + +// return pair of iterator and boolean +return {it, res.second}; +} + +/*! + @brief inserts element + + Inserts element @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] val element to insert + @return iterator pointing to the inserted @a val. + + @throw type_error.309 if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Constant plus linear in the distance between @a pos and end of + the container. + + @liveexample{The example shows how `insert()` is used.,insert} + + @since version 1.0.0 + */ +iterator insert(const_iterator pos, const basic_json& val) +{ +// insert only works for arrays +if (JSON_LIKELY(is_array())) +{ +// check if iterator pos fits to this JSON value +if (JSON_UNLIKELY(pos.m_object != this)) +{ +JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); +} + +// insert to array and return iterator +iterator result(this); +result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); +return result; +} + +JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); +} + +/*! + @brief inserts element + @copydoc insert(const_iterator, const basic_json&) + */ +iterator insert(const_iterator pos, basic_json&& val) +{ +return insert(pos, val); +} + +/*! + @brief inserts elements + + Inserts @a cnt copies of @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] cnt number of copies of @a val to insert + @param[in] val element to insert + @return iterator pointing to the first element inserted, or @a pos if + `cnt==0` + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Linear in @a cnt plus linear in the distance between @a pos + and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__count} + + @since version 1.0.0 + */ +iterator insert(const_iterator pos, size_type cnt, const basic_json& val) +{ +// insert only works for arrays +if (JSON_LIKELY(is_array())) +{ +// check if iterator pos fits to this JSON value +if (JSON_UNLIKELY(pos.m_object != this)) +{ +JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); +} + +// insert to array and return iterator +iterator result(this); +result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); +return result; +} + +JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); +} + +/*! + @brief inserts elements + + Inserts elements from range `[first, last)` before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + @throw invalid_iterator.211 if @a first or @a last are iterators into + container for which insert is called; example: `"passed iterators may not + belong to container"` + + @return iterator pointing to the first element inserted, or @a pos if + `first==last` + + @complexity Linear in `std::distance(first, last)` plus linear in the + distance between @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__range} + + @since version 1.0.0 + */ +iterator insert(const_iterator pos, const_iterator first, const_iterator last) +{ +// insert only works for arrays +if (JSON_UNLIKELY(not is_array())) +{ +JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); +} + +// check if iterator pos fits to this JSON value +if (JSON_UNLIKELY(pos.m_object != this)) +{ +JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); +} + +// check if range iterators belong to the same JSON object +if (JSON_UNLIKELY(first.m_object != last.m_object)) +{ +JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); +} + +if (JSON_UNLIKELY(first.m_object == this)) +{ +JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container")); +} + +// insert to array and return iterator +iterator result(this); +result.m_it.array_iterator = m_value.array->insert( +pos.m_it.array_iterator, +first.m_it.array_iterator, +last.m_it.array_iterator); +return result; +} + +/*! + @brief inserts elements + + Inserts elements from initializer list @a ilist before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] ilist initializer list to insert the values from + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @return iterator pointing to the first element inserted, or @a pos if + `ilist` is empty + + @complexity Linear in `ilist.size()` plus linear in the distance between + @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__ilist} + + @since version 1.0.0 + */ +iterator insert(const_iterator pos, initializer_list_t ilist) +{ +// insert only works for arrays +if (JSON_UNLIKELY(not is_array())) +{ +JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); +} + +// check if iterator pos fits to this JSON value +if (JSON_UNLIKELY(pos.m_object != this)) +{ +JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); +} + +// insert to array and return iterator +iterator result(this); +result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end()); +return result; +} + +/*! + @brief inserts elements + + Inserts elements from range `[first, last)`. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than objects; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number + of elements to insert. + + @liveexample{The example shows how `insert()` is used.,insert__range_object} + + @since version 3.0.0 + */ +void insert(const_iterator first, const_iterator last) +{ +// insert only works for objects +if (JSON_UNLIKELY(not is_object())) +{ +JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); +} + +// check if range iterators belong to the same JSON object +if (JSON_UNLIKELY(first.m_object != last.m_object)) +{ +JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); +} + +// passed iterators must belong to objects +if (JSON_UNLIKELY(not first.m_object->is_object())) +{ +JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); +} + +m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); +} + +/*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from JSON object @a j and overwrites existing keys. + + @param[in] j JSON object to read values from + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ +void update(const_reference j) +{ +// implicitly convert null value to an empty object +if (is_null()) +{ +m_type = value_t::object; +m_value.object = create(); +assert_invariant(); +} + +if (JSON_UNLIKELY(not is_object())) +{ +JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); +} +if (JSON_UNLIKELY(not j.is_object())) +{ +JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()))); +} + +for (auto it = j.cbegin(); it != j.cend(); ++it) +{ +m_value.object->operator[](it.key()) = it.value(); +} +} + +/*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from from range `[first, last)` and overwrites existing + keys. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used__range.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ +void update(const_iterator first, const_iterator last) +{ +// implicitly convert null value to an empty object +if (is_null()) +{ +m_type = value_t::object; +m_value.object = create(); +assert_invariant(); +} + +if (JSON_UNLIKELY(not is_object())) +{ +JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); +} + +// check if range iterators belong to the same JSON object +if (JSON_UNLIKELY(first.m_object != last.m_object)) +{ +JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); +} + +// passed iterators must belong to objects +if (JSON_UNLIKELY(not first.m_object->is_object() +or not first.m_object->is_object())) +{ +JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); +} + +for (auto it = first; it != last; ++it) +{ +m_value.object->operator[](it.key()) = it.value(); +} +} + +/*! + @brief exchanges the values + + Exchanges the contents of the JSON value with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ +void swap(reference other) noexcept ( +std::is_nothrow_move_constructible::value and +std::is_nothrow_move_assignable::value and +std::is_nothrow_move_constructible::value and +std::is_nothrow_move_assignable::value +) +{ +std::swap(m_type, other.m_type); +std::swap(m_value, other.m_value); +assert_invariant(); +} + +/*! + @brief exchanges the values + + Exchanges the contents of a JSON array with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other array to exchange the contents with + + @throw type_error.310 when JSON value is not an array; example: `"cannot + use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how arrays can be swapped with + `swap()`.,swap__array_t} + + @since version 1.0.0 + */ +void swap(array_t& other) +{ +// swap only works for arrays +if (JSON_LIKELY(is_array())) +{ +std::swap(*(m_value.array), other); +} +else +{ +JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); +} +} + +/*! + @brief exchanges the values + + Exchanges the contents of a JSON object with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other object to exchange the contents with + + @throw type_error.310 when JSON value is not an object; example: + `"cannot use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how objects can be swapped with + `swap()`.,swap__object_t} + + @since version 1.0.0 + */ +void swap(object_t& other) +{ +// swap only works for objects +if (JSON_LIKELY(is_object())) +{ +std::swap(*(m_value.object), other); +} +else +{ +JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); +} +} + +/*! + @brief exchanges the values + + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other string to exchange the contents with + + @throw type_error.310 when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. + + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__string_t} + + @since version 1.0.0 + */ +void swap(string_t& other) +{ +// swap only works for strings +if (JSON_LIKELY(is_string())) +{ +std::swap(*(m_value.string), other); +} +else +{ +JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); +} +} + +/// @} + +public: +////////////////////////////////////////// +// lexicographical comparison operators // +////////////////////////////////////////// + +/// @name lexicographical comparison operators +/// @{ + +/*! + @brief comparison: equal + + Compares two JSON values for equality according to the following rules: + - Two JSON values are equal if (1) they are from the same type and (2) + their stored values are the same according to their respective + `operator==`. + - Integer and floating-point numbers are automatically converted before + comparison. Note than two NaN values are always treated as unequal. + - Two JSON null values are equal. + + @note Floating-point inside JSON values numbers are compared with + `json::number_float_t::operator==` which is `double::operator==` by + default. To compare floating-point while respecting an epsilon, an alternative + [comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39) + could be used, for instance + @code {.cpp} + template::value, T>::type> + inline bool is_same(T a, T b, T epsilon = std::numeric_limits::epsilon()) noexcept + { + return std::abs(a - b) <= epsilon; + } + @endcode + + @note NaN values never compare equal to themselves or to other NaN values. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are equal + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__equal} + + @since version 1.0.0 + */ +friend bool operator==(const_reference lhs, const_reference rhs) noexcept +{ +const auto lhs_type = lhs.type(); +const auto rhs_type = rhs.type(); + +if (lhs_type == rhs_type) +{ +switch (lhs_type) +{ +case value_t::array: +return (*lhs.m_value.array == *rhs.m_value.array); + +case value_t::object: +return (*lhs.m_value.object == *rhs.m_value.object); + +case value_t::null: +return true; + +case value_t::string: +return (*lhs.m_value.string == *rhs.m_value.string); + +case value_t::boolean: +return (lhs.m_value.boolean == rhs.m_value.boolean); + +case value_t::number_integer: +return (lhs.m_value.number_integer == rhs.m_value.number_integer); + +case value_t::number_unsigned: +return (lhs.m_value.number_unsigned == rhs.m_value.number_unsigned); + +case value_t::number_float: +return (lhs.m_value.number_float == rhs.m_value.number_float); + +default: +return false; +} +} +else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) +{ +return (static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float); +} +else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) +{ +return (lhs.m_value.number_float == static_cast(rhs.m_value.number_integer)); +} +else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) +{ +return (static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float); +} +else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) +{ +return (lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned)); +} +else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) +{ +return (static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer); +} +else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) +{ +return (lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned)); +} + +return false; +} + +/*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept +{ +return (lhs == basic_json(rhs)); +} + +/*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept +{ +return (basic_json(lhs) == rhs); +} + +/*! + @brief comparison: not equal + + Compares two JSON values for inequality by calculating `not (lhs == rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are not equal + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__notequal} + + @since version 1.0.0 + */ +friend bool operator!=(const_reference lhs, const_reference rhs) noexcept +{ +return not (lhs == rhs); +} + +/*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept +{ +return (lhs != basic_json(rhs)); +} + +/*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept +{ +return (basic_json(lhs) != rhs); +} + +/*! + @brief comparison: less than + + Compares whether one JSON value @a lhs is less than another JSON value @a + rhs according to the following rules: + - If @a lhs and @a rhs have the same type, the values are compared using + the default `<` operator. + - Integer and floating-point numbers are automatically converted before + comparison + - In case @a lhs and @a rhs have different types, the values are ignored + and the order of the types is considered, see + @ref operator<(const value_t, const value_t). + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__less} + + @since version 1.0.0 + */ +friend bool operator<(const_reference lhs, const_reference rhs) noexcept +{ +const auto lhs_type = lhs.type(); +const auto rhs_type = rhs.type(); + +if (lhs_type == rhs_type) +{ +switch (lhs_type) +{ +case value_t::array: +return (*lhs.m_value.array) < (*rhs.m_value.array); + +case value_t::object: +return *lhs.m_value.object < *rhs.m_value.object; + +case value_t::null: +return false; + +case value_t::string: +return *lhs.m_value.string < *rhs.m_value.string; + +case value_t::boolean: +return lhs.m_value.boolean < rhs.m_value.boolean; + +case value_t::number_integer: +return lhs.m_value.number_integer < rhs.m_value.number_integer; + +case value_t::number_unsigned: +return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; + +case value_t::number_float: +return lhs.m_value.number_float < rhs.m_value.number_float; + +default: +return false; +} +} +else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) +{ +return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; +} +else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) +{ +return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); +} +else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) +{ +return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; +} +else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) +{ +return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); +} +else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) +{ +return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); +} +else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) +{ +return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; +} + +// We only reach this line if we cannot compare values. In that case, +// we compare types. Note we have to call the operator explicitly, +// because MSVC has problems otherwise. +return operator<(lhs_type, rhs_type); +} + +/*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept +{ +return (lhs < basic_json(rhs)); +} + +/*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept +{ +return (basic_json(lhs) < rhs); +} + +/*! + @brief comparison: less than or equal + + Compares whether one JSON value @a lhs is less than or equal to another + JSON value by calculating `not (rhs < lhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greater} + + @since version 1.0.0 + */ +friend bool operator<=(const_reference lhs, const_reference rhs) noexcept +{ +return not (rhs < lhs); +} + +/*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept +{ +return (lhs <= basic_json(rhs)); +} + +/*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept +{ +return (basic_json(lhs) <= rhs); +} + +/*! + @brief comparison: greater than + + Compares whether one JSON value @a lhs is greater than another + JSON value by calculating `not (lhs <= rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__lessequal} + + @since version 1.0.0 + */ +friend bool operator>(const_reference lhs, const_reference rhs) noexcept +{ +return not (lhs <= rhs); +} + +/*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept +{ +return (lhs > basic_json(rhs)); +} + +/*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept +{ +return (basic_json(lhs) > rhs); +} + +/*! + @brief comparison: greater than or equal + + Compares whether one JSON value @a lhs is greater than or equal to another + JSON value by calculating `not (lhs < rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greaterequal} + + @since version 1.0.0 + */ +friend bool operator>=(const_reference lhs, const_reference rhs) noexcept +{ +return not (lhs < rhs); +} + +/*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept +{ +return (lhs >= basic_json(rhs)); +} + +/*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept +{ +return (basic_json(lhs) >= rhs); +} + +/// @} + +/////////////////// +// serialization // +/////////////////// + +/// @name serialization +/// @{ + +/*! + @brief serialize to stream + + Serialize the given JSON value @a j to the output stream @a o. The JSON + value will be serialized using the @ref dump member function. + + - The indentation of the output can be controlled with the member variable + `width` of the output stream @a o. For instance, using the manipulator + `std::setw(4)` on @a o sets the indentation level to `4` and the + serialization result is the same as calling `dump(4)`. + + - The indentation character can be controlled with the member variable + `fill` of the output stream @a o. For instance, the manipulator + `std::setfill('\\t')` sets indentation to use a tab character rather than + the default space character. + + @param[in,out] o stream to serialize to + @param[in] j JSON value to serialize + + @return the stream @a o + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded + + @complexity Linear. + + @liveexample{The example below shows the serialization with different + parameters to `width` to adjust the indentation level.,operator_serialize} + + @since version 1.0.0; indentation character added in version 3.0.0 + */ +friend std::ostream& operator<<(std::ostream& o, const basic_json& j) +{ +// read width member and use it as indentation parameter if nonzero +const bool pretty_print = (o.width() > 0); +const auto indentation = (pretty_print ? o.width() : 0); + +// reset width to 0 for subsequent calls to this stream +o.width(0); + +// do the actual serialization +serializer s(detail::output_adapter(o), o.fill()); +s.dump(j, pretty_print, false, static_cast(indentation)); +return o; +} + +/*! + @brief serialize to stream + @deprecated This stream operator is deprecated and will be removed in + future 4.0.0 of the library. Please use + @ref operator<<(std::ostream&, const basic_json&) + instead; that is, replace calls like `j >> o;` with `o << j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ +JSON_DEPRECATED +friend std::ostream& operator>>(const basic_json& j, std::ostream& o) +{ +return o << j; +} + +/// @} + + +///////////////////// +// deserialization // +///////////////////// + +/// @name deserialization +/// @{ + +/*! + @brief deserialize from a compatible input + + This function reads from a compatible input. Examples are: + - an array of 1-byte values + - strings with character/literal type with size of 1 byte + - input streams + - container with contiguous storage of 1-byte values. Compatible container + types include `std::vector`, `std::string`, `std::array`, + `std::valarray`, and `std::initializer_list`. Furthermore, C-style + arrays can be used with `std::begin()`/`std::end()`. User-defined + containers can be used as long as they implement random-access iterators + and a contiguous storage. + + @pre Each element of the container has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @pre The container storage is contiguous. Violating this precondition + yields undefined behavior. **This precondition is enforced with an + assertion.** + @pre Each element of the container has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @warning There is no way to enforce all preconditions at compile-time. If + the function is called with a noncompliant container and with + assertions switched off, the behavior is undefined and will most + likely yield segmentation violation. + + @param[in] i input to read from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an array.,parse__array__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__string__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__istream__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function reading + from a contiguous container.,parse__contiguouscontainer__parser_callback_t} + + @since version 2.0.3 (contiguous containers) + */ +static basic_json parse(detail::input_adapter i, +const parser_callback_t cb = nullptr, +const bool allow_exceptions = true) +{ +basic_json result; +parser(i, cb, allow_exceptions).parse(true, result); +return result; +} + +/*! + @copydoc basic_json parse(detail::input_adapter, const parser_callback_t) + */ +static basic_json parse(detail::input_adapter& i, +const parser_callback_t cb = nullptr, +const bool allow_exceptions = true) +{ +basic_json result; +parser(i, cb, allow_exceptions).parse(true, result); +return result; +} + +static bool accept(detail::input_adapter i) +{ +return parser(i).accept(true); +} + +static bool accept(detail::input_adapter& i) +{ +return parser(i).accept(true); +} + +/*! + @brief deserialize from an iterator range with contiguous storage + + This function reads from an iterator range of a container with contiguous + storage of 1-byte values. Compatible container types include + `std::vector`, `std::string`, `std::array`, `std::valarray`, and + `std::initializer_list`. Furthermore, C-style arrays can be used with + `std::begin()`/`std::end()`. User-defined containers can be used as long + as they implement random-access iterators and a contiguous storage. + + @pre The iterator range is contiguous. Violating this precondition yields + undefined behavior. **This precondition is enforced with an assertion.** + @pre Each element in the range has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @warning There is no way to enforce all preconditions at compile-time. If + the function is called with noncompliant iterators and with + assertions switched off, the behavior is undefined and will most + likely yield segmentation violation. + + @tparam IteratorType iterator of container with contiguous storage + @param[in] first begin of the range to parse (included) + @param[in] last end of the range to parse (excluded) + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return result of the deserialization + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an iterator range.,parse__iteratortype__parser_callback_t} + + @since version 2.0.3 + */ +template::iterator_category>::value, int>::type = 0> +static basic_json parse(IteratorType first, IteratorType last, +const parser_callback_t cb = nullptr, +const bool allow_exceptions = true) +{ +basic_json result; +parser(detail::input_adapter(first, last), cb, allow_exceptions).parse(true, result); +return result; +} + +template::iterator_category>::value, int>::type = 0> +static bool accept(IteratorType first, IteratorType last) +{ +return parser(detail::input_adapter(first, last)).accept(true); +} + +/*! + @brief deserialize from stream + @deprecated This stream operator is deprecated and will be removed in + version 4.0.0 of the library. Please use + @ref operator>>(std::istream&, basic_json&) + instead; that is, replace calls like `j << i;` with `i >> j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ +JSON_DEPRECATED +friend std::istream& operator<<(basic_json& j, std::istream& i) +{ +return operator>>(i, j); +} + +/*! + @brief deserialize from stream + + Deserializes an input stream to a JSON value. + + @param[in,out] i input stream to read a serialized JSON value from + @param[in,out] j JSON value to write the deserialized input to + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below shows how a JSON value is constructed by + reading a serialization from a stream.,operator_deserialize} + + @sa parse(std::istream&, const parser_callback_t) for a variant with a + parser callback function to filter values while parsing + + @since version 1.0.0 + */ +friend std::istream& operator>>(std::istream& i, basic_json& j) +{ +parser(detail::input_adapter(i)).parse(false, j); +return i; +} + +/// @} + +/////////////////////////// +// convenience functions // +/////////////////////////// + +/*! + @brief return the type as string + + Returns the type name as string to be used in error messages - usually to + indicate that a function was called on a wrong JSON type. + + @return a string representation of a the @a m_type member: + Value type | return value + ----------- | ------------- + null | `"null"` + boolean | `"boolean"` + string | `"string"` + number | `"number"` (for all number types) + object | `"object"` + array | `"array"` + discarded | `"discarded"` + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Constant. + + @liveexample{The following code exemplifies `type_name()` for all JSON + types.,type_name} + + @sa @ref type() -- return the type of the JSON value + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + + @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept` + since 3.0.0 + */ +const char* type_name() const noexcept +{ +{ +switch (m_type) +{ +case value_t::null: +return "null"; +case value_t::object: +return "object"; +case value_t::array: +return "array"; +case value_t::string: +return "string"; +case value_t::boolean: +return "boolean"; +case value_t::discarded: +return "discarded"; +default: +return "number"; +} +} +} + + +private: +////////////////////// +// member variables // +////////////////////// + +/// the type of the current element +value_t m_type = value_t::null; + +/// the value of the current element +json_value m_value = {}; + +////////////////////////////////////////// +// binary serialization/deserialization // +////////////////////////////////////////// + +/// @name binary serialization/deserialization support +/// @{ + +public: +/*! + @brief create a CBOR serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the CBOR (Concise + Binary Object Representation) serialization format. CBOR is a binary + serialization format which aims to be more compact than JSON itself, yet + more efficient to parse. + + The library uses the following mapping from JSON values types to + CBOR types according to the CBOR specification (RFC 7049): + + JSON value type | value/range | CBOR type | first byte + --------------- | ------------------------------------------ | ---------------------------------- | --------------- + null | `null` | Null | 0xF6 + boolean | `true` | True | 0xF5 + boolean | `false` | False | 0xF4 + number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B + number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A + number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 + number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 + number_integer | -24..-1 | Negative integer | 0x20..0x37 + number_integer | 0..23 | Integer | 0x00..0x17 + number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_unsigned | 0..23 | Integer | 0x00..0x17 + number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_float | *any value* | Double-Precision Float | 0xFB + string | *length*: 0..23 | UTF-8 string | 0x60..0x77 + string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 + string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 + string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7A + string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7B + array | *size*: 0..23 | array | 0x80..0x97 + array | *size*: 23..255 | array (1 byte follow) | 0x98 + array | *size*: 256..65535 | array (2 bytes follow) | 0x99 + array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9A + array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9B + object | *size*: 0..23 | map | 0xA0..0xB7 + object | *size*: 23..255 | map (1 byte follow) | 0xB8 + object | *size*: 256..65535 | map (2 bytes follow) | 0xB9 + object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xBA + object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a CBOR value. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @note The following CBOR types are not used in the conversion: + - byte strings (0x40..0x5F) + - UTF-8 strings terminated by "break" (0x7F) + - arrays terminated by "break" (0x9F) + - maps terminated by "break" (0xBF) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - tagged items (0xC6..0xD4, 0xD8..0xDB) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + - half and single-precision floats (0xF9-0xFA) + - break (0xFF) + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in CBOR format.,to_cbor} + + @sa http://cbor.io + @sa @ref from_cbor(detail::input_adapter, const bool strict) for the + analogous deserialization + @sa @ref to_msgpack(const basic_json&) for the related MessagePack format + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9 + */ +static std::vector to_cbor(const basic_json& j) +{ +std::vector result; +to_cbor(j, result); +return result; +} + +static void to_cbor(const basic_json& j, detail::output_adapter o) +{ +binary_writer(o).write_cbor(j); +} + +static void to_cbor(const basic_json& j, detail::output_adapter o) +{ +binary_writer(o).write_cbor(j); +} + +/*! + @brief create a MessagePack serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the MessagePack + serialization format. MessagePack is a binary serialization format which + aims to be more compact than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + MessagePack types according to the MessagePack specification: + + JSON value type | value/range | MessagePack type | first byte + --------------- | --------------------------------- | ---------------- | ---------- + null | `null` | nil | 0xC0 + boolean | `true` | true | 0xC3 + boolean | `false` | false | 0xC2 + number_integer | -9223372036854775808..-2147483649 | int64 | 0xD3 + number_integer | -2147483648..-32769 | int32 | 0xD2 + number_integer | -32768..-129 | int16 | 0xD1 + number_integer | -128..-33 | int8 | 0xD0 + number_integer | -32..-1 | negative fixint | 0xE0..0xFF + number_integer | 0..127 | positive fixint | 0x00..0x7F + number_integer | 128..255 | uint 8 | 0xCC + number_integer | 256..65535 | uint 16 | 0xCD + number_integer | 65536..4294967295 | uint 32 | 0xCE + number_integer | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_unsigned | 0..127 | positive fixint | 0x00..0x7F + number_unsigned | 128..255 | uint 8 | 0xCC + number_unsigned | 256..65535 | uint 16 | 0xCD + number_unsigned | 65536..4294967295 | uint 32 | 0xCE + number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_float | *any value* | float 64 | 0xCB + string | *length*: 0..31 | fixstr | 0xA0..0xBF + string | *length*: 32..255 | str 8 | 0xD9 + string | *length*: 256..65535 | str 16 | 0xDA + string | *length*: 65536..4294967295 | str 32 | 0xDB + array | *size*: 0..15 | fixarray | 0x90..0x9F + array | *size*: 16..65535 | array 16 | 0xDC + array | *size*: 65536..4294967295 | array 32 | 0xDD + object | *size*: 0..15 | fix map | 0x80..0x8F + object | *size*: 16..65535 | map 16 | 0xDE + object | *size*: 65536..4294967295 | map 32 | 0xDF + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a MessagePack value. + + @note The following values can **not** be converted to a MessagePack value: + - strings with more than 4294967295 bytes + - arrays with more than 4294967295 elements + - objects with more than 4294967295 elements + + @note The following MessagePack types are not used in the conversion: + - bin 8 - bin 32 (0xC4..0xC6) + - ext 8 - ext 32 (0xC7..0xC9) + - float 32 (0xCA) + - fixext 1 - fixext 16 (0xD4..0xD8) + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in MessagePack format.,to_msgpack} + + @sa http://msgpack.org + @sa @ref from_msgpack(const std::vector&, const size_t) for the + analogous deserialization + @sa @ref to_cbor(const basic_json& for the related CBOR format + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9 + */ +static std::vector to_msgpack(const basic_json& j) +{ +std::vector result; +to_msgpack(j, result); +return result; +} + +static void to_msgpack(const basic_json& j, detail::output_adapter o) +{ +binary_writer(o).write_msgpack(j); +} + +static void to_msgpack(const basic_json& j, detail::output_adapter o) +{ +binary_writer(o).write_msgpack(j); +} + +/*! + @brief create a UBJSON serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the UBJSON + (Universal Binary JSON) serialization format. UBJSON aims to be more compact + than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + UBJSON types according to the UBJSON specification: + + JSON value type | value/range | UBJSON type | marker + --------------- | --------------------------------- | ----------- | ------ + null | `null` | null | `Z` + boolean | `true` | true | `T` + boolean | `false` | false | `F` + number_integer | -9223372036854775808..-2147483649 | int64 | `L` + number_integer | -2147483648..-32769 | int32 | `l` + number_integer | -32768..-129 | int16 | `I` + number_integer | -128..127 | int8 | `i` + number_integer | 128..255 | uint8 | `U` + number_integer | 256..32767 | int16 | `I` + number_integer | 32768..2147483647 | int32 | `l` + number_integer | 2147483648..9223372036854775807 | int64 | `L` + number_unsigned | 0..127 | int8 | `i` + number_unsigned | 128..255 | uint8 | `U` + number_unsigned | 256..32767 | int16 | `I` + number_unsigned | 32768..2147483647 | int32 | `l` + number_unsigned | 2147483648..9223372036854775807 | int64 | `L` + number_float | *any value* | float64 | `D` + string | *with shortest length indicator* | string | `S` + array | *see notes on optimized format* | array | `[` + object | *see notes on optimized format* | map | `{` + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a UBJSON value. + + @note The following values can **not** be converted to a UBJSON value: + - strings with more than 9223372036854775807 bytes (theoretical) + - unsigned integer numbers above 9223372036854775807 + + @note The following markers are not used in the conversion: + - `Z`: no-op values are not created. + - `C`: single-byte strings are serialized with `S` markers. + + @note Any UBJSON output created @ref to_ubjson can be successfully parsed + by @ref from_ubjson. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @note The optimized formats for containers are supported: Parameter + @a use_size adds size information to the beginning of a container and + removes the closing marker. Parameter @a use_type further checks + whether all elements of a container have the same type and adds the + type marker to the beginning of the container. The @a use_type + parameter must only be used together with @a use_size = true. Note + that @a use_size = true alone may result in larger representations - + the benefit of this parameter is that the receiving side is + immediately informed on the number of elements of the container. + + @param[in] j JSON value to serialize + @param[in] use_size whether to add size annotations to container types + @param[in] use_type whether to add type annotations to container types + (must be combined with @a use_size = true) + @return UBJSON serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in UBJSON format.,to_ubjson} + + @sa http://ubjson.org + @sa @ref from_ubjson(detail::input_adapter, const bool strict) for the + analogous deserialization + @sa @ref to_cbor(const basic_json& for the related CBOR format + @sa @ref to_msgpack(const basic_json&) for the related MessagePack format + + @since version 3.1.0 + */ +static std::vector to_ubjson(const basic_json& j, +const bool use_size = false, +const bool use_type = false) +{ +std::vector result; +to_ubjson(j, result, use_size, use_type); +return result; +} + +static void to_ubjson(const basic_json& j, detail::output_adapter o, +const bool use_size = false, const bool use_type = false) +{ +binary_writer(o).write_ubjson(j, use_size, use_type); +} + +static void to_ubjson(const basic_json& j, detail::output_adapter o, +const bool use_size = false, const bool use_type = false) +{ +binary_writer(o).write_ubjson(j, use_size, use_type); +} + +/*! + @brief create a JSON value from an input in CBOR format + + Deserializes a given input @a i to a JSON value using the CBOR (Concise + Binary Object Representation) serialization format. + + The library maps CBOR types to JSON value types as follows: + + CBOR type | JSON value type | first byte + ---------------------- | --------------- | ---------- + Integer | number_unsigned | 0x00..0x17 + Unsigned integer | number_unsigned | 0x18 + Unsigned integer | number_unsigned | 0x19 + Unsigned integer | number_unsigned | 0x1A + Unsigned integer | number_unsigned | 0x1B + Negative integer | number_integer | 0x20..0x37 + Negative integer | number_integer | 0x38 + Negative integer | number_integer | 0x39 + Negative integer | number_integer | 0x3A + Negative integer | number_integer | 0x3B + Negative integer | number_integer | 0x40..0x57 + UTF-8 string | string | 0x60..0x77 + UTF-8 string | string | 0x78 + UTF-8 string | string | 0x79 + UTF-8 string | string | 0x7A + UTF-8 string | string | 0x7B + UTF-8 string | string | 0x7F + array | array | 0x80..0x97 + array | array | 0x98 + array | array | 0x99 + array | array | 0x9A + array | array | 0x9B + array | array | 0x9F + map | object | 0xA0..0xB7 + map | object | 0xB8 + map | object | 0xB9 + map | object | 0xBA + map | object | 0xBB + map | object | 0xBF + False | `false` | 0xF4 + True | `true` | 0xF5 + Nill | `null` | 0xF6 + Half-Precision Float | number_float | 0xF9 + Single-Precision Float | number_float | 0xFA + Double-Precision Float | number_float | 0xFB + + @warning The mapping is **incomplete** in the sense that not all CBOR + types can be converted to a JSON value. The following CBOR types + are not supported and will yield parse errors (parse_error.112): + - byte strings (0x40..0x5F) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - tagged items (0xC6..0xD4, 0xD8..0xDB) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + + @warning CBOR allows map keys of any type, whereas JSON only allows + strings as keys in object values. Therefore, CBOR maps with keys + other than UTF-8 strings are rejected (parse_error.113). + + @note Any CBOR output created @ref to_cbor can be successfully parsed by + @ref from_cbor. + + @param[in] i an input in CBOR format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @return deserialized JSON value + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from CBOR were + used in the given input @a v or if the input is not valid CBOR + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in CBOR + format to a JSON value.,from_cbor} + + @sa http://cbor.io + @sa @ref to_cbor(const basic_json&) for the analogous serialization + @sa @ref from_msgpack(detail::input_adapter, const bool) for the + related MessagePack format + @sa @ref from_ubjson(detail::input_adapter, const bool) for the related + UBJSON format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0 + */ +static basic_json from_cbor(detail::input_adapter i, +const bool strict = true) +{ +return binary_reader(i).parse_cbor(strict); +} + +/*! + @copydoc from_cbor(detail::input_adapter, const bool) + */ +template::value, int> = 0> +static basic_json from_cbor(A1 && a1, A2 && a2, const bool strict = true) +{ +return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_cbor(strict); +} + +/*! + @brief create a JSON value from an input in MessagePack format + + Deserializes a given input @a i to a JSON value using the MessagePack + serialization format. + + The library maps MessagePack types to JSON value types as follows: + + MessagePack type | JSON value type | first byte + ---------------- | --------------- | ---------- + positive fixint | number_unsigned | 0x00..0x7F + fixmap | object | 0x80..0x8F + fixarray | array | 0x90..0x9F + fixstr | string | 0xA0..0xBF + nil | `null` | 0xC0 + false | `false` | 0xC2 + true | `true` | 0xC3 + float 32 | number_float | 0xCA + float 64 | number_float | 0xCB + uint 8 | number_unsigned | 0xCC + uint 16 | number_unsigned | 0xCD + uint 32 | number_unsigned | 0xCE + uint 64 | number_unsigned | 0xCF + int 8 | number_integer | 0xD0 + int 16 | number_integer | 0xD1 + int 32 | number_integer | 0xD2 + int 64 | number_integer | 0xD3 + str 8 | string | 0xD9 + str 16 | string | 0xDA + str 32 | string | 0xDB + array 16 | array | 0xDC + array 32 | array | 0xDD + map 16 | object | 0xDE + map 32 | object | 0xDF + negative fixint | number_integer | 0xE0-0xFF + + @warning The mapping is **incomplete** in the sense that not all + MessagePack types can be converted to a JSON value. The following + MessagePack types are not supported and will yield parse errors: + - bin 8 - bin 32 (0xC4..0xC6) + - ext 8 - ext 32 (0xC7..0xC9) + - fixext 1 - fixext 16 (0xD4..0xD8) + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @param[in] i an input in MessagePack format convertible to an input + adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from MessagePack were + used in the given input @a i or if the input is not valid MessagePack + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + MessagePack format to a JSON value.,from_msgpack} + + @sa http://msgpack.org + @sa @ref to_msgpack(const basic_json&) for the analogous serialization + @sa @ref from_cbor(detail::input_adapter, const bool) for the related CBOR + format + @sa @ref from_ubjson(detail::input_adapter, const bool) for the related + UBJSON format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0 + */ +static basic_json from_msgpack(detail::input_adapter i, +const bool strict = true) +{ +return binary_reader(i).parse_msgpack(strict); +} + +/*! + @copydoc from_msgpack(detail::input_adapter, const bool) + */ +template::value, int> = 0> +static basic_json from_msgpack(A1 && a1, A2 && a2, const bool strict = true) +{ +return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_msgpack(strict); +} + +/*! + @brief create a JSON value from an input in UBJSON format + + Deserializes a given input @a i to a JSON value using the UBJSON (Universal + Binary JSON) serialization format. + + The library maps UBJSON types to JSON value types as follows: + + UBJSON type | JSON value type | marker + ----------- | --------------------------------------- | ------ + no-op | *no value, next value is read* | `N` + null | `null` | `Z` + false | `false` | `F` + true | `true` | `T` + float32 | number_float | `d` + float64 | number_float | `D` + uint8 | number_unsigned | `U` + int8 | number_integer | `i` + int16 | number_integer | `I` + int32 | number_integer | `l` + int64 | number_integer | `L` + string | string | `S` + char | string | `C` + array | array (optimized values are supported) | `[` + object | object (optimized values are supported) | `{` + + @note The mapping is **complete** in the sense that any UBJSON value can + be converted to a JSON value. + + @param[in] i an input in UBJSON format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if a parse error occurs + @throw parse_error.113 if a string could not be parsed successfully + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + UBJSON format to a JSON value.,from_ubjson} + + @sa http://ubjson.org + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + analogous serialization + @sa @ref from_cbor(detail::input_adapter, const bool) for the related CBOR + format + @sa @ref from_msgpack(detail::input_adapter, const bool) for the related + MessagePack format + + @since version 3.1.0 + */ +static basic_json from_ubjson(detail::input_adapter i, +const bool strict = true) +{ +return binary_reader(i).parse_ubjson(strict); +} + +template::value, int> = 0> +static basic_json from_ubjson(A1 && a1, A2 && a2, const bool strict = true) +{ +return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_ubjson(strict); +} + +/// @} + +////////////////////////// +// JSON Pointer support // +////////////////////////// + +/// @name JSON Pointer functions +/// @{ + +/*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. Similar to @ref operator[](const typename + object_t::key_type&), `null` values are created in arrays and objects if + necessary. + + In particular: + - If the JSON pointer points to an object key that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. + - If the JSON pointer points to an array index that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. All indices between the current maximum and the given + index are also filled with `null`. + - The special value `-` is treated as a synonym for the index past the + end. + + @param[in] ptr a JSON pointer + + @return reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer} + + @since version 2.0.0 + */ +reference operator[](const json_pointer& ptr) +{ +return ptr.get_unchecked(this); +} + +/*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. The function does not change the JSON + value; no `null` values are created. In particular, the the special value + `-` yields an exception. + + @param[in] ptr JSON pointer to the desired element + + @return const reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} + + @since version 2.0.0 + */ +const_reference operator[](const json_pointer& ptr) const +{ +return ptr.get_unchecked(this); +} + +/*! + @brief access specified element via JSON Pointer + + Returns a reference to the element at with specified JSON pointer @a ptr, + with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer} + */ +reference at(const json_pointer& ptr) +{ +return ptr.get_checked(this); +} + +/*! + @brief access specified element via JSON Pointer + + Returns a const reference to the element at with specified JSON pointer @a + ptr, with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer_const} + */ +const_reference at(const json_pointer& ptr) const +{ +return ptr.get_checked(this); +} + +/*! + @brief return flattened JSON value + + The function creates a JSON object whose keys are JSON pointers (see [RFC + 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all + primitive. The original JSON value can be restored using the @ref + unflatten() function. + + @return an object that maps JSON pointers to primitive values + + @note Empty objects and arrays are flattened to `null` and will not be + reconstructed correctly by the @ref unflatten() function. + + @complexity Linear in the size the JSON value. + + @liveexample{The following code shows how a JSON object is flattened to an + object whose keys consist of JSON pointers.,flatten} + + @sa @ref unflatten() for the reverse function + + @since version 2.0.0 + */ +basic_json flatten() const +{ +basic_json result(value_t::object); +json_pointer::flatten("", *this, result); +return result; +} + +/*! + @brief unflatten a previously flattened JSON value + + The function restores the arbitrary nesting of a JSON value that has been + flattened before using the @ref flatten() function. The JSON value must + meet certain constraints: + 1. The value must be an object. + 2. The keys must be JSON pointers (see + [RFC 6901](https://tools.ietf.org/html/rfc6901)) + 3. The mapped values must be primitive JSON types. + + @return the original JSON from a flattened version + + @note Empty objects and arrays are flattened by @ref flatten() to `null` + values and can not unflattened to their original type. Apart from + this example, for a JSON value `j`, the following is always true: + `j == j.flatten().unflatten()`. + + @complexity Linear in the size the JSON value. + + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + + @liveexample{The following code shows how a flattened JSON object is + unflattened into the original nested JSON object.,unflatten} + + @sa @ref flatten() for the reverse function + + @since version 2.0.0 + */ +basic_json unflatten() const +{ +return json_pointer::unflatten(*this); +} + +/// @} + +////////////////////////// +// JSON Patch functions // +////////////////////////// + +/// @name JSON Patch functions +/// @{ + +/*! + @brief applies a JSON patch + + [JSON Patch](http://jsonpatch.com) defines a JSON document structure for + expressing a sequence of operations to apply to a JSON) document. With + this function, a JSON Patch is applied to the current JSON value by + executing all operations from the patch. + + @param[in] json_patch JSON patch document + @return patched document + + @note The application of a patch is atomic: Either all operations succeed + and the patched document is returned or an exception is thrown. In + any case, the original value is not changed: the patch is applied + to a copy of the value. + + @throw parse_error.104 if the JSON patch does not consist of an array of + objects + + @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory + attributes are missing); example: `"operation add must have member path"` + + @throw out_of_range.401 if an array index is out of range. + + @throw out_of_range.403 if a JSON pointer inside the patch could not be + resolved successfully in the current JSON value; example: `"key baz not + found"` + + @throw out_of_range.405 if JSON pointer has no parent ("add", "remove", + "move") + + @throw other_error.501 if "test" operation was unsuccessful + + @complexity Linear in the size of the JSON value and the length of the + JSON patch. As usually only a fraction of the JSON value is affected by + the patch, the complexity can usually be neglected. + + @liveexample{The following code shows how a JSON patch is applied to a + value.,patch} + + @sa @ref diff -- create a JSON patch by comparing two JSON values + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) + + @since version 2.0.0 + */ +basic_json patch(const basic_json& json_patch) const +{ +// make a working copy to apply the patch to +basic_json result = *this; + +// the valid JSON Patch operations +enum class patch_operations {add, remove, replace, move, copy, test, invalid}; + +const auto get_op = [](const std::string & op) +{ +if (op == "add") +{ +return patch_operations::add; +} +if (op == "remove") +{ +return patch_operations::remove; +} +if (op == "replace") +{ +return patch_operations::replace; +} +if (op == "move") +{ +return patch_operations::move; +} +if (op == "copy") +{ +return patch_operations::copy; +} +if (op == "test") +{ +return patch_operations::test; +} + +return patch_operations::invalid; +}; + +// wrapper for "add" operation; add value at ptr +const auto operation_add = [&result](json_pointer & ptr, basic_json val) +{ +// adding to the root of the target document means replacing it +if (ptr.is_root()) +{ +result = val; +} +else +{ +// make sure the top element of the pointer exists +json_pointer top_pointer = ptr.top(); +if (top_pointer != ptr) +{ +result.at(top_pointer); +} + +// get reference to parent of JSON pointer ptr +const auto last_path = ptr.pop_back(); +basic_json& parent = result[ptr]; + +switch (parent.m_type) +{ +case value_t::null: +case value_t::object: +{ +// use operator[] to add value +parent[last_path] = val; +break; +} + +case value_t::array: +{ +if (last_path == "-") +{ +// special case: append to back +parent.push_back(val); +} +else +{ +const auto idx = json_pointer::array_index(last_path); +if (JSON_UNLIKELY(static_cast(idx) > parent.size())) +{ +// avoid undefined behavior +JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); +} +else +{ +// default case: insert add offset +parent.insert(parent.begin() + static_cast(idx), val); +} +} +break; +} + +default: +{ +// if there exists a parent it cannot be primitive +assert(false); // LCOV_EXCL_LINE +} +} +} +}; + +// wrapper for "remove" operation; remove value at ptr +const auto operation_remove = [&result](json_pointer & ptr) +{ +// get reference to parent of JSON pointer ptr +const auto last_path = ptr.pop_back(); +basic_json& parent = result.at(ptr); + +// remove child +if (parent.is_object()) +{ +// perform range check +auto it = parent.find(last_path); +if (JSON_LIKELY(it != parent.end())) +{ +parent.erase(it); +} +else +{ +JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found")); +} +} +else if (parent.is_array()) +{ +// note erase performs range check +parent.erase(static_cast(json_pointer::array_index(last_path))); +} +}; + +// type check: top level value must be an array +if (JSON_UNLIKELY(not json_patch.is_array())) +{ +JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); +} + +// iterate and apply the operations +for (const auto& val : json_patch) +{ +// wrapper to get a value for an operation +const auto get_value = [&val](const std::string & op, +const std::string & member, +bool string_type) -> basic_json & +{ +// find value +auto it = val.m_value.object->find(member); + +// context-sensitive error message +const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; + +// check if desired value is present +if (JSON_UNLIKELY(it == val.m_value.object->end())) +{ +JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'")); +} + +// check if result is of type string +if (JSON_UNLIKELY(string_type and not it->second.is_string())) +{ +JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'")); +} + +// no error: return value +return it->second; +}; + +// type check: every element of the array must be an object +if (JSON_UNLIKELY(not val.is_object())) +{ +JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); +} + +// collect mandatory members +const std::string op = get_value("op", "op", true); +const std::string path = get_value(op, "path", true); +json_pointer ptr(path); + +switch (get_op(op)) +{ +case patch_operations::add: +{ +operation_add(ptr, get_value("add", "value", false)); +break; +} + +case patch_operations::remove: +{ +operation_remove(ptr); +break; +} + +case patch_operations::replace: +{ +// the "path" location must exist - use at() +result.at(ptr) = get_value("replace", "value", false); +break; +} + +case patch_operations::move: +{ +const std::string from_path = get_value("move", "from", true); +json_pointer from_ptr(from_path); + +// the "from" location must exist - use at() +basic_json v = result.at(from_ptr); + +// The move operation is functionally identical to a +// "remove" operation on the "from" location, followed +// immediately by an "add" operation at the target +// location with the value that was just removed. +operation_remove(from_ptr); +operation_add(ptr, v); +break; +} + +case patch_operations::copy: +{ +const std::string from_path = get_value("copy", "from", true); +const json_pointer from_ptr(from_path); + +// the "from" location must exist - use at() +basic_json v = result.at(from_ptr); + +// The copy is functionally identical to an "add" +// operation at the target location using the value +// specified in the "from" member. +operation_add(ptr, v); +break; +} + +case patch_operations::test: +{ +bool success = false; +JSON_TRY +{ +// check if "value" matches the one at "path" +// the "path" location must exist - use at() +success = (result.at(ptr) == get_value("test", "value", false)); +} +JSON_CATCH (out_of_range&) +{ +// ignore out of range errors: success remains false +} + +// throw an exception if test fails +if (JSON_UNLIKELY(not success)) +{ +JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump())); +} + +break; +} + +case patch_operations::invalid: +{ +// op must be "add", "remove", "replace", "move", "copy", or +// "test" +JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid")); +} +} +} + +return result; +} + +/*! + @brief creates a diff as a JSON patch + + Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can + be changed into the value @a target by calling @ref patch function. + + @invariant For two JSON values @a source and @a target, the following code + yields always `true`: + @code {.cpp} + source.patch(diff(source, target)) == target; + @endcode + + @note Currently, only `remove`, `add`, and `replace` operations are + generated. + + @param[in] source JSON value to compare from + @param[in] target JSON value to compare against + @param[in] path helper value to create JSON pointers + + @return a JSON patch to convert the @a source to @a target + + @complexity Linear in the lengths of @a source and @a target. + + @liveexample{The following code shows how a JSON patch is created as a + diff for two JSON values.,diff} + + @sa @ref patch -- apply a JSON patch + @sa @ref merge_patch -- apply a JSON Merge Patch + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + + @since version 2.0.0 + */ +static basic_json diff(const basic_json& source, const basic_json& target, +const std::string& path = "") +{ +// the patch +basic_json result(value_t::array); + +// if the values are the same, return empty patch +if (source == target) +{ +return result; +} + +if (source.type() != target.type()) +{ +// different types: replace value +result.push_back( +{ +{"op", "replace"}, {"path", path}, {"value", target} +}); +} +else +{ +switch (source.type()) +{ +case value_t::array: +{ +// first pass: traverse common elements +std::size_t i = 0; +while (i < source.size() and i < target.size()) +{ +// recursive call to compare array values at index i +auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); +result.insert(result.end(), temp_diff.begin(), temp_diff.end()); +++i; +} + +// i now reached the end of at least one array +// in a second pass, traverse the remaining elements + +// remove my remaining elements +const auto end_index = static_cast(result.size()); +while (i < source.size()) +{ +// add operations in reverse order to avoid invalid +// indices +result.insert(result.begin() + end_index, object( +{ +{"op", "remove"}, +{"path", path + "/" + std::to_string(i)} +})); +++i; +} + +// add other remaining elements +while (i < target.size()) +{ +result.push_back( +{ +{"op", "add"}, +{"path", path + "/" + std::to_string(i)}, +{"value", target[i]} +}); +++i; +} + +break; +} + +case value_t::object: +{ +// first pass: traverse this object's elements +for (auto it = source.cbegin(); it != source.cend(); ++it) +{ +// escape the key name to be used in a JSON patch +const auto key = json_pointer::escape(it.key()); + +if (target.find(it.key()) != target.end()) +{ +// recursive call to compare object values at key it +auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); +result.insert(result.end(), temp_diff.begin(), temp_diff.end()); +} +else +{ +// found a key that is not in o -> remove it +result.push_back(object( +{ +{"op", "remove"}, {"path", path + "/" + key} +})); +} +} + +// second pass: traverse other object's elements +for (auto it = target.cbegin(); it != target.cend(); ++it) +{ +if (source.find(it.key()) == source.end()) +{ +// found a key that is not in this -> add it +const auto key = json_pointer::escape(it.key()); +result.push_back( +{ +{"op", "add"}, {"path", path + "/" + key}, +{"value", it.value()} +}); +} +} + +break; +} + +default: +{ +// both primitive type: replace value +result.push_back( +{ +{"op", "replace"}, {"path", path}, {"value", target} +}); +break; +} +} +} + +return result; +} + +/// @} + +//////////////////////////////// +// JSON Merge Patch functions // +//////////////////////////////// + +/// @name JSON Merge Patch functions +/// @{ + +/*! + @brief applies a JSON Merge Patch + + The merge patch format is primarily intended for use with the HTTP PATCH + method as a means of describing a set of modifications to a target + resource's content. This function applies a merge patch to the current + JSON value. + + The function implements the following algorithm from Section 2 of + [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396): + + ``` + define MergePatch(Target, Patch): + if Patch is an Object: + if Target is not an Object: + Target = {} // Ignore the contents and set it to an empty Object + for each Name/Value pair in Patch: + if Value is null: + if Name exists in Target: + remove the Name/Value pair from Target + else: + Target[Name] = MergePatch(Target[Name], Value) + return Target + else: + return Patch + ``` + + Thereby, `Target` is the current object; that is, the patch is applied to + the current value. + + @param[in] patch the patch to apply + + @complexity Linear in the lengths of @a patch. + + @liveexample{The following code shows how a JSON Merge Patch is applied to + a JSON document.,merge_patch} + + @sa @ref patch -- apply a JSON patch + @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396) + + @since version 3.0.0 + */ +void merge_patch(const basic_json& patch) +{ +if (patch.is_object()) +{ +if (not is_object()) +{ +*this = object(); +} +for (auto it = patch.begin(); it != patch.end(); ++it) +{ +if (it.value().is_null()) +{ +erase(it.key()); +} +else +{ +operator[](it.key()).merge_patch(it.value()); +} +} +} +else +{ +*this = patch; +} +} + +/// @} +}; +} // namespace nlohmann + +/////////////////////// +// nonmember support // +/////////////////////// + +// specialization of std::swap, and std::hash +namespace std +{ +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template<> +inline void swap(nlohmann::json& j1, +nlohmann::json& j2) noexcept( +is_nothrow_move_constructible::value and +is_nothrow_move_assignable::value +) +{ +j1.swap(j2); +} + +/// hash value for JSON objects +template<> +struct hash +{ +/*! + @brief return a hash value for a JSON object + + @since version 1.0.0 + */ +std::size_t operator()(const nlohmann::json& j) const +{ +// a naive hashing via the string representation +const auto& h = hash(); +return h(j.dump()); +} +}; + +/// specialization for std::less +/// @note: do not remove the space after '<', +/// see https://github.com/nlohmann/json/pull/679 +template<> +struct less< ::nlohmann::detail::value_t> +{ +/*! + @brief compare two value_t enum values + @since version 3.0.0 + */ +bool operator()(nlohmann::detail::value_t lhs, +nlohmann::detail::value_t rhs) const noexcept +{ +return nlohmann::detail::operator<(lhs, rhs); +} +}; + +} // namespace std + +/*! +@brief user-defined string literal for JSON values + +This operator implements a user-defined string literal for JSON objects. It +can be used by adding `"_json"` to a string literal and returns a JSON object +if no parse error occurred. + +@param[in] s a string representation of a JSON object +@param[in] n the length of string @a s +@return a JSON object + +@since version 1.0.0 +*/ +inline nlohmann::json operator "" _json(const char* s, std::size_t n) +{ +return nlohmann::json::parse(s, s + n); +} + +/*! +@brief user-defined string literal for JSON pointer + +This operator implements a user-defined string literal for JSON Pointers. It +can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer +object if no parse error occurred. + +@param[in] s a string representation of a JSON Pointer +@param[in] n the length of string @a s +@return a JSON pointer object + +@since version 2.0.0 +*/ +inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) +{ +return nlohmann::json::json_pointer(std::string(s, n)); +} + +// #include + + +// restore GCC/clang diagnostic settings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic pop +#endif +#if defined(__clang__) +#pragma GCC diagnostic pop +#endif + +// clean up +#undef JSON_CATCH +#undef JSON_THROW +#undef JSON_TRY +#undef JSON_LIKELY +#undef JSON_UNLIKELY +#undef JSON_DEPRECATED +#undef JSON_HAS_CPP_14 +#undef JSON_HAS_CPP_17 +#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION +#undef NLOHMANN_BASIC_JSON_TPL +#undef NLOHMANN_JSON_HAS_HELPER + + +#endif \ No newline at end of file diff --git a/splinter/include/json_parser.h b/splinter/include/json_parser.h new file mode 100644 index 0000000000..363583374b --- /dev/null +++ b/splinter/include/json_parser.h @@ -0,0 +1,29 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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 SPLINTER_JSON_PARSER_H +#define SPLINTER_JSON_PARSER_H + +#include + +namespace SPLINTER +{ + +class BSpline; +class DataTable; + +void bspline_to_json(const BSpline &bspline, const std::string &filename); +BSpline bspline_from_json(const std::string &filename); + +void datatable_to_json(const DataTable &data, const std::string &filename); +DataTable datatable_from_json(const std::string &filename); + +} // namespace SPLINTER + +#endif //SPLINTER_JSON_PARSER_H diff --git a/splinter/include/knot_builders.h b/splinter/include/knot_builders.h new file mode 100644 index 0000000000..0f0738db3b --- /dev/null +++ b/splinter/include/knot_builders.h @@ -0,0 +1,97 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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 SPLINTER_KNOT_UTILS_H +#define SPLINTER_KNOT_UTILS_H + +#include +#include + +namespace SPLINTER +{ + +/** + * B-spline knot spacing + */ +enum class KnotSpacing { + /* + * Experimental knot spacing for testing purposes only. + * Currently, it computes equidistant knots on an expanded interval. + * NOTE: may change in the future + */ + EXPERIMENTAL, + + /* + * Clamped and with knots that mimic the spacing of sample points using a moving average filter. + * Resulting knot vectors have p+1 multiplicity of end knots. This is the default knot spacing for B-spline + * interpolation and smoothing. + * Example for samples at 0, 1, ..., 5: + * Then, for degree 3 the knot vector becomes: [0, 0, 0, 0, 2, 3, 5, 5, 5, 5] + * and for degree 1 the knot vector becomes: [0, 0, 1, 2, 3, 4, 5, 5] + */ + AS_SAMPLED, + + /* + * Clamped knot vector with equidistant internal knots. p+1 multiplicity of end knots. + * Example for samples at 0, 1, ..., 5: + * For degree 3: [0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5] + * For degree 1: [0, 0, 1, 2, 3, 4, 5, 5] + */ + EQUIDISTANT_CLAMPED, + + /* + * Simple knot vector with equidistant knots. Single multiplicity of end knots. Does not vary with degree. + * Example for samples at 0, 1, ..., 5: + * For degree 3: [0, 1, 2, 3, 4, 5] + * For degree 1: [0, 1, 2, 3, 4, 5] + */ + EQUIDISTANT +}; + +/** + * Computing knot vectors + */ +std::vector> build_knot_vectors(const DataTable &data, const std::vector °rees); + +std::vector> build_knot_vectors(const DataTable &data, const std::vector °rees, + KnotSpacing knot_spacing, + const std::vector &num_basis_functions); + +/** + * Computing single knot vector + */ +std::vector build_knot_vector(const std::vector &values, unsigned int degree, + unsigned int num_basis_functions, KnotSpacing knot_spacing); + +/** + * Construct knot vector using moving average filter (AS_SAMPLED) + */ +std::vector knot_vector_moving_average(const std::vector &values, unsigned int degree); + +/** + * Compute clamped, equidistant knot vector (EQUIDISTANT_CLAMPED) + */ +std::vector knot_vector_equidistant_clamped(const std::vector &values, unsigned int degree, + unsigned int num_basis_functions = 0); + +/** + * Construct equidistant knot vector (EQUIDISTANT) + */ +std::vector knot_vector_equidistant(const std::vector &values, unsigned int degree, + unsigned int num_basis_functions); + +/** + * Construct expanded equidistant knot vector (EXPERIMENTAL) + */ +std::vector knot_vector_expanded_equidistant(const std::vector &values, unsigned int degree, + unsigned int num_basis_functions); + +} // namespace SPLINTER + +#endif // SPLINTER_KNOT_UTILS_H diff --git a/splinter/include/knot_vector.h b/splinter/include/knot_vector.h new file mode 100644 index 0000000000..22d022cca5 --- /dev/null +++ b/splinter/include/knot_vector.h @@ -0,0 +1,106 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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 SPLINTER_KNOT_VECTOR_H +#define SPLINTER_KNOT_VECTOR_H + +#include +#include +#include "definitions.h" + +namespace SPLINTER +{ + +/** + * Class representing a knot vector (nondecreasing sequence of number) + */ +class KnotVector +{ +public: + KnotVector() + : knots(std::vector()) + { + } + + KnotVector(const std::vector &knots) + : knots(std::vector(knots)) + { + // Test knots here + if (!is_nondecreasing()) + throw Exception("KnotVector::KnotVector: Knot vector is not nondecreasing."); + } + + std::vector get_values() const { + // Return copy of knots + return knots; + } + + bool is_nondecreasing() const { + return std::is_sorted(knots.begin(), knots.end()); + } + + bool is_regular(unsigned int degree) const; + + bool is_clamped(unsigned int degree) const; + + bool is_refinement(const KnotVector &refined_knots) const { + return is_refinement(refined_knots.get_values()); + } + + bool is_refinement(const std::vector &refined_knots) const; + + bool is_supported(double x) const { + return (knots.front() <= x) && (x <= knots.back()); + } + + unsigned int multiplicity(double tau) const { + return (unsigned int)std::count(knots.begin(), knots.end(), tau); + } + + unsigned int index_interval(double x) const; + + std::vector::size_type size() const { + return knots.size(); + } + + bool empty() const { + return knots.empty(); + } + + std::vector::const_iterator cbegin() const { + return knots.cbegin(); + } + + std::vector::const_iterator cend() const { + return knots.cend(); + } + + const double& at(unsigned int i) const { + return knots.at(i); + } + + const double& front() const { + return knots.front(); + } + + const double& back() const { + return knots.back(); + } + +private: + std::vector knots; + +}; + +bool operator==(const KnotVector &lhs, const KnotVector &rhs); +bool operator!=(const KnotVector &lhs, const KnotVector &rhs); + +} // namespace SPLINTER + +#endif // SPLINTER_KNOT_VECTOR_H diff --git a/splinter/mykroneckerproduct.h b/splinter/include/kronecker_product.h similarity index 52% rename from splinter/mykroneckerproduct.h rename to splinter/include/kronecker_product.h index 7e5254df4a..8701004c91 100644 --- a/splinter/mykroneckerproduct.h +++ b/splinter/include/kronecker_product.h @@ -7,21 +7,21 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef SPLINTER_MYKRONECKERPRODUCT_H -#define SPLINTER_MYKRONECKERPRODUCT_H +#ifndef SPLINTER_KRONECKER_PRODUCT_H +#define SPLINTER_KRONECKER_PRODUCT_H #include "definitions.h" namespace SPLINTER { -SparseMatrix myKroneckerProduct(const SparseMatrix &A, const SparseMatrix &B); +SparseMatrix my_kronecker_product(const SparseMatrix &A, const SparseMatrix &B); // Apply Kronecker product on several vectors or matrices -SparseVector kroneckerProductVectors(const std::vector &vectors); -DenseVector kroneckerProductVectors(const std::vector &vectors); -SparseMatrix kroneckerProductMatrices(const std::vector &matrices); +SparseVector kronecker_product_vectors(const std::vector &vectors); +DenseVector kronecker_product_vectors(const std::vector &vectors); +SparseMatrix kronecker_product_matrices(const std::vector &matrices); } // namespace SPLINTER -#endif // SPLINTER_MYKRONECKERPRODUCT_H +#endif // SPLINTER_KRONECKER_PRODUCT_H diff --git a/splinter/linearsolvers.h b/splinter/include/linear_solvers.h similarity index 64% rename from splinter/linearsolvers.h rename to splinter/include/linear_solvers.h index f2b319af9b..5a9f5b2791 100644 --- a/splinter/linearsolvers.h +++ b/splinter/include/linear_solvers.h @@ -7,16 +7,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef SPLINTER_LINEARSOLVER_H -#define SPLINTER_LINEARSOLVER_H +#ifndef SPLINTER_LINEAR_SOLVER_H +#define SPLINTER_LINEAR_SOLVER_H #include "definitions.h" #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push -// fails CentOS 7 #pragma GCC diagnostic ignored "-Wignored-attributes" +#pragma GCC diagnostic ignored "-Wignored-attributes" #endif -#include "IterativeLinearSolvers" -#include "SparseQR" +#include "Eigen/IterativeLinearSolvers" +#include "Eigen/SparseQR" #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif @@ -30,15 +30,15 @@ class LinearSolver public: bool solve(const lhs &A, const rhs &b, rhs &x) const { - if (!consistentData(A, b)) + if (!consistent_data(A, b)) throw Exception("LinearSolver::solve: Inconsistent matrix dimensions!"); - bool success = doSolve(A, b, x); + bool success = do_solve(A, b, x); if (!success) throw Exception("LinearSolver::solve: Solver did not converge to acceptable tolerance!"); -// if (!validSolution(A, b, x)) +// if (!valid_solution(A, b, x)) // throw Exception("LinearSolver::solve: Invalid solution!"); return true; @@ -48,14 +48,14 @@ class LinearSolver private: double tol = 1e-12; // Relative error tolerance - virtual bool doSolve(const lhs &A, const rhs &b, rhs &x) const = 0; + virtual bool do_solve(const lhs &A, const rhs &b, rhs &x) const = 0; - bool consistentData(const lhs &A, const rhs &b) const + bool consistent_data(const lhs &A, const rhs &b) const { return A.rows() == b.rows(); } - bool validSolution(const lhs &A, const rhs &b, const rhs &x) const + bool valid_solution(const lhs &A, const rhs &b, const rhs &x) const { //return b.isApprox(A*x); double err = (A*x - b).norm() / b.norm(); @@ -68,7 +68,7 @@ template class DenseSVD : public LinearSolver { private: - bool doSolve(const DenseMatrix &A, const rhs &b, rhs &x) const + bool do_solve(const DenseMatrix &A, const rhs &b, rhs &x) const { // Solve linear system Eigen::JacobiSVD svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV); @@ -81,7 +81,7 @@ template class DenseQR : public LinearSolver { private: - bool doSolve(const DenseMatrix &A, const rhs &b, rhs &x) const + bool do_solve(const DenseMatrix &A, const rhs &b, rhs &x) const { //x = A.colPivHouseholderQr().solve(b); @@ -103,17 +103,17 @@ template class SparseBiCG : public LinearSolver { private: - bool doSolve(const SparseMatrix &A, const rhs &b, rhs &x) const + bool do_solve(const SparseMatrix &A, const rhs &b, rhs &x) const { // Init BiCGSTAB solver (requires square matrices) - Eigen::BiCGSTAB sparseSolver(A); + Eigen::BiCGSTAB sparse_solver(A); - if (sparseSolver.info() == Eigen::Success) + if (sparse_solver.info() == Eigen::Success) { // Solve LSE - x = sparseSolver.solve(b); + x = sparse_solver.solve(b); - return sparseSolver.info() == Eigen::Success; + return sparse_solver.info() == Eigen::Success; } return false; @@ -124,21 +124,21 @@ template class SparseLU : public LinearSolver { private: - bool doSolve(const SparseMatrix &A, const rhs &b, rhs &x) const + bool do_solve(const SparseMatrix &A, const rhs &b, rhs &x) const { // Init SparseLU solver (requires square matrices) - Eigen::SparseLU sparseSolver; + Eigen::SparseLU sparse_solver; // Compute the ordering permutation vector from the structural pattern of A - sparseSolver.analyzePattern(A); + sparse_solver.analyzePattern(A); // Compute the numerical factorization - sparseSolver.factorize(A); + sparse_solver.factorize(A); - if (sparseSolver.info() == Eigen::Success) + if (sparse_solver.info() == Eigen::Success) { // Solve LSE - x = sparseSolver.solve(b); + x = sparse_solver.solve(b); - return sparseSolver.info() == Eigen::Success; + return sparse_solver.info() == Eigen::Success; } return false; @@ -149,19 +149,19 @@ template class SparseQR : public LinearSolver { private: - bool doSolve(const SparseMatrix &A, const rhs &b, rhs &x) const + bool do_solve(const SparseMatrix &A, const rhs &b, rhs &x) const { // Init SparseQR solver (works with rectangular matrices) - Eigen::SparseQR> sparseSolver; - sparseSolver.analyzePattern(A); - sparseSolver.factorize(A); + Eigen::SparseQR> sparse_solver; + sparse_solver.analyzePattern(A); + sparse_solver.factorize(A); - if (sparseSolver.info() == Eigen::Success) + if (sparse_solver.info() == Eigen::Success) { // Solve LSE - x = sparseSolver.solve(b); + x = sparse_solver.solve(b); - return sparseSolver.info() == Eigen::Success; + return sparse_solver.info() == Eigen::Success; } return false; @@ -170,4 +170,4 @@ class SparseQR : public LinearSolver } // namespace SPLINTER -#endif // SPLINTER_LINEARSOLVER_H +#endif // SPLINTER_LINEAR_SOLVER_H diff --git a/splinter/include/utilities.h b/splinter/include/utilities.h new file mode 100644 index 0000000000..276c702d2f --- /dev/null +++ b/splinter/include/utilities.h @@ -0,0 +1,59 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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 SPLINTER_UTILITIES_H +#define SPLINTER_UTILITIES_H + +#include +#include // For std::abs, etc. +#include + +namespace SPLINTER +{ + +// Compare two numbers +template +bool assert_near(T x, T y, double tolAbs = 1e-8, double tolRel = 1e-8) +{ + double dx = std::abs(x - y); + double xAbs = 0.5*(std::abs(x) + std::abs(y)); + double err = std::max(tolAbs, tolRel*xAbs); + return dx < err; +} + +// Compare two vectors +inline bool compare_vectors(std::vector x, std::vector y, double tolAbs = 1e-8, double tolRel = 1e-8) +{ + if (x.size() != y.size()) + return false; + + for (unsigned int i = 0; i < x.size(); ++i) + if (!assert_near(x.at(i), y.at(i), tolAbs, tolRel)) + return false; + + return true; +} + +std::vector eig_to_std_vec(const DenseVector &vec); + +DenseVector std_to_eig_vec(const std::vector &vec); + +std::vector> eig_to_std_mat(const DenseMatrix &mat); + +DenseMatrix std_to_eig_mat(const std::vector> &vec); + +std::vector linspace(double start, double stop, unsigned int num); + +std::vector extract_unique_sorted(const std::vector &values); + +std::vector> transpose_vec_vec(std::vector> x); + +} // namespace SPLINTER + +#endif // SPLINTER_UTILITIES_H diff --git a/splinter/knots.cpp b/splinter/knots.cpp deleted file mode 100644 index 371c5ca492..0000000000 --- a/splinter/knots.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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/. -*/ - -#include -#include "knots.h" - -namespace SPLINTER -{ - -bool isKnotVectorRegular(const std::vector &knots, unsigned int degree) -{ - // Check size - if (knots.size() < 2 * (degree + 1)) - return false; - - // Check order - if (!std::is_sorted(knots.begin(), knots.end())) - return false; - - // Check multiplicity of knots - for (std::vector::const_iterator it = knots.begin(); it != knots.end(); ++it) - { - if (count(knots.begin(), knots.end(), *it) > degree + 1) - return false; - } - - return true; -} - -bool isKnotVectorClamped(const std::vector &knots, unsigned int degree) -{ - // Check multiplicity of first knot - if (std::count(knots.begin(), knots.begin() + degree + 1, knots.front()) != degree + 1) - return false; - - // Check multiplicity of last knot - if (std::count(knots.end() - degree - 1, knots.end(), knots.back()) != degree + 1) - return false; - - return true; -} - -bool isKnotVectorRefinement(const std::vector &knots, const std::vector &refinedKnots) -{ - // Check size - if (refinedKnots.size() < knots.size()) - return false; - - // Check that each element in knots occurs at least as many times in refinedKnots - for (std::vector::const_iterator it = knots.begin() ; it != knots.end(); ++it) - { - int m_tau = count(knots.begin(), knots.end(), *it); - int m_t = count(refinedKnots.begin(), refinedKnots.end(), *it); - if (m_t < m_tau) return false; - } - - // Check that range is not changed - if (knots.front() != refinedKnots.front()) return false; - if (knots.back() != refinedKnots.back()) return false; - - return true; -} - -} // namespace SPLINTER diff --git a/splinter/knots.h b/splinter/knots.h deleted file mode 100644 index 399bc54fda..0000000000 --- a/splinter/knots.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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 SPLINTER_KNOTS_H -#define SPLINTER_KNOTS_H - -#include - -namespace SPLINTER -{ - -// Knot vector related -bool isKnotVectorRegular(const std::vector &knots, unsigned int degree); -bool isKnotVectorClamped(const std::vector &knots, unsigned int degree); -bool isKnotVectorRefinement(const std::vector &knots, const std::vector &refinedKnots); - -} // namespace SPLINTER - -#endif // SPLINTER_KNOTS_H diff --git a/splinter/saveable.h b/splinter/saveable.h deleted file mode 100644 index db2c4a668b..0000000000 --- a/splinter/saveable.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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 SPLINTER_SAVEABLE_H -#define SPLINTER_SAVEABLE_H - -namespace SPLINTER -{ - -/** - * Interface for save and load functionality - */ -class Saveable -{ -public: - Saveable() {} - virtual ~Saveable() {} - - /** - * Serialize and save object to fileName - * Should throw exception if file could not be opened - */ - virtual void save(const std::string &fileName) const = 0; - -protected: - /** - * Deserialize and load object from fileName - * Should throw exception if file could not be opened - * or if the file format is wrong - */ - virtual void load(const std::string &fileName) = 0; -}; - -} // namespace SPLINTER - -#endif // SPLINTER_SAVEABLE_H diff --git a/splinter/serializer.cpp b/splinter/serializer.cpp deleted file mode 100644 index 1c8ad8a077..0000000000 --- a/splinter/serializer.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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/. -*/ - -#include "serializer.h" -#include -#include "definitions.h" -#include "datapoint.h" -#include "datatable.h" -#include "bspline.h" -#include "bsplinebasis.h" -#include "bsplinebasis1d.h" - -namespace SPLINTER -{ - -Serializer::Serializer() -{ - stream = StreamType(0); -} - -Serializer::Serializer(const std::string &fileName) -{ - stream = StreamType(0); - loadFromFile(fileName); -} - -void Serializer::saveToFile(const std::string &fileName) -{ - std::fstream fs(fileName, std::fstream::out | std::fstream::binary); - - for (const auto& byte : stream) - fs << byte; -} - -void Serializer::loadFromFile(const std::string &fileName) -{ - // Open the file in binary mode at the end - std::ifstream ifs(fileName, std::ios::binary | std::ios::ate); - - if (!ifs.is_open()) { - std::string error_message("Serializer::loadFromFile: Unable to open file \""); - error_message.append(fileName); - error_message.append("\" for deserializing."); - throw Exception(error_message); - } - - // Because we opened the file at the end, tellg() will give us the size of the file - std::ifstream::pos_type pos = ifs.tellg(); - - std::vector result(pos); - - ifs.seekg(0, std::ios::beg); - - // http://www.cplusplus.com/reference/vector/vector/data/ - // Elements of the vector are guaranteed to be stored in a contiguous array, - // *result.data() can therefore be treated as an array of the same type as the vector - ifs.read(result.data(), pos); - //assert(ifs); - - stream.clear(); - // Convert from char to uint_8 vector - for (const char& byte : result) - stream.push_back((uint8_t)byte); - - read = stream.cbegin(); -} - -/* - * get_size implementations - */ - -size_t Serializer::get_size(const DataPoint &obj) -{ - return get_size(obj.x) + get_size(obj.y); -} - -size_t Serializer::get_size(const DataTable &obj) -{ - return get_size(obj.allowDuplicates) - + get_size(obj.allowIncompleteGrid) - + get_size(obj.numDuplicates) - + get_size(obj.numVariables) - + get_size(obj.samples) - + get_size(obj.grid); -} - -size_t Serializer::get_size(const BSpline &obj) -{ - return get_size(obj.basis) - + get_size(obj.knotaverages) - + get_size(obj.coefficients) - + get_size(obj.numVariables); -} - -size_t Serializer::get_size(const BSplineBasis &obj) -{ - return get_size(obj.bases) - + get_size(obj.numVariables); -} - -size_t Serializer::get_size(const BSplineBasis1D &obj) -{ - return get_size(obj.degree) - + get_size(obj.knots) - + get_size(obj.targetNumBasisfunctions); -} - -size_t Serializer::get_size(const DenseMatrix &obj) -{ - size_t size = sizeof(obj.rows()); - size += sizeof(obj.cols()); - size_t numElements = obj.rows() * obj.cols(); - if (numElements > 0) { - size += numElements * sizeof(obj(0,0)); - } - return size; -} - -size_t Serializer::get_size(const DenseVector &obj) -{ - size_t size = sizeof(obj.rows()); - size_t numElements = obj.rows(); - if (numElements > 0) { - size += numElements * sizeof(obj(0)); - } - return size; -} - -size_t Serializer::get_size(const SparseMatrix &obj) -{ - DenseMatrix temp(obj); - return get_size(temp); -} - -size_t Serializer::get_size(const SparseVector &obj) -{ - DenseVector temp(obj); - return get_size(temp); -} - -/* - * _serialize implementations - */ - -void Serializer::_serialize(const DataPoint &obj) -{ - _serialize(obj.x); - _serialize(obj.y); -} - -void Serializer::_serialize(const DataTable &obj) -{ - _serialize(obj.allowDuplicates); - _serialize(obj.allowIncompleteGrid); - _serialize(obj.numDuplicates); - _serialize(obj.numVariables); - _serialize(obj.samples); - _serialize(obj.grid); -} - -void Serializer::_serialize(const BSpline &obj) -{ - _serialize(obj.basis); - _serialize(obj.knotaverages); - _serialize(obj.coefficients); - _serialize(obj.numVariables); -} - -void Serializer::_serialize(const BSplineBasis &obj) -{ - _serialize(obj.bases); - _serialize(obj.numVariables); -} - -void Serializer::_serialize(const BSplineBasis1D &obj) -{ - _serialize(obj.degree); - _serialize(obj.knots); - _serialize(obj.targetNumBasisfunctions); -} - -void Serializer::_serialize(const DenseMatrix &obj) -{ - // Store the number of matrix rows and columns first - _serialize(obj.rows()); - _serialize(obj.cols()); - // Store the matrix elements - for (size_t i = 0; i < (size_t) obj.rows(); ++i) { - for (size_t j = 0; j < (size_t) obj.cols(); ++j) { - _serialize(obj(i,j)); - } - } -} - -void Serializer::_serialize(const DenseVector &obj) -{ - // Store the number of vector rows - _serialize(obj.rows()); - // Store the vector elements - for (size_t i = 0; i < (size_t) obj.rows(); ++i) { - _serialize(obj(i)); - } -} - -void Serializer::_serialize(const SparseMatrix &obj) -{ - DenseMatrix temp(obj); - _serialize(temp); -} - -void Serializer::_serialize(const SparseVector &obj) -{ - DenseVector temp(obj); - _serialize(temp); -} - -/* - * deserialize implementations - */ - -void Serializer::deserialize(DataPoint &obj) -{ - deserialize(obj.x); - deserialize(obj.y); -} - -void Serializer::deserialize(DataTable &obj) -{ - deserialize(obj.allowDuplicates); - deserialize(obj.allowIncompleteGrid); - deserialize(obj.numDuplicates); - deserialize(obj.numVariables); - deserialize(obj.samples); - deserialize(obj.grid); -} - -void Serializer::deserialize(BSpline &obj) -{ - deserialize(obj.basis); - deserialize(obj.knotaverages); - deserialize(obj.coefficients); - deserialize(obj.numVariables); -} - -void Serializer::deserialize(BSplineBasis &obj) -{ - deserialize(obj.bases); - deserialize(obj.numVariables); -} - -void Serializer::deserialize(BSplineBasis1D &obj) -{ - deserialize(obj.degree); - deserialize(obj.knots); - deserialize(obj.targetNumBasisfunctions); -} - -void Serializer::deserialize(DenseMatrix &obj) -{ - // Retrieve the number of rows - size_t rows; deserialize(rows); - size_t cols; deserialize(cols); - - obj.resize(rows, cols); - - for (size_t i = 0; i < rows; ++i) - { - for (size_t j = 0; j < cols; ++j) - { - deserialize(obj(i, j)); - } - } -} - -void Serializer::deserialize(DenseVector &obj) -{ - // Retrieve the number of rows - size_t rows; deserialize(rows); - - obj.resize(rows); - - for (size_t i = 0; i < rows; ++i) - { - deserialize(obj(i)); - } -} - -void Serializer::deserialize(SparseMatrix &obj) -{ - DenseMatrix temp(obj); - deserialize(temp); - obj = temp.sparseView(); -} - -void Serializer::deserialize(SparseVector &obj) -{ - DenseVector temp(obj); - deserialize(temp); - obj = temp.sparseView(); -} - -} // namespace SPLINTER diff --git a/splinter/serializer.h b/splinter/serializer.h deleted file mode 100644 index 82cb073fc9..0000000000 --- a/splinter/serializer.h +++ /dev/null @@ -1,308 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * 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 SPLINTER_SERIALIZER_H -#define SPLINTER_SERIALIZER_H - -#include -#include -#include -#include "definitions.h" -#include -#include -#include - -namespace SPLINTER -{ - -class DataPoint; -class DataTable; -class BSpline; -class BSplineBasis; -class BSplineBasis1D; - -/** - * Class for serialization - * NOTE: member variables must be serialized and deserialized in the same order. - * NOTE2: Serialization / deserialization of SparseMatrix/SparseVector works by first converting to - * DenseMatrix/DenseVector and vice versa. - */ -class Serializer -{ -public: - Serializer(); - Serializer(const std::string &fileName); - - virtual ~Serializer() {} - - // Serialize obj into the internal stream - template - void serialize(const T &obj); - - template - void deserialize(T &obj); - - template - void deserialize(std::vector &obj); - - template - void deserialize(std::set &obj); - - template - void deserialize(std::multiset &obj); - - void deserialize(DenseMatrix &obj); - void deserialize(DenseVector &obj); - void deserialize(SparseMatrix &obj); - void deserialize(SparseVector &obj); - - void deserialize(DataPoint &obj); - void deserialize(DataTable &obj); - void deserialize(BSpline &obj); - void deserialize(BSplineBasis &obj); - void deserialize(BSplineBasis1D &obj); - - // Save the serialized stream to fileName - void saveToFile(const std::string &fileName); - - // Load fileName into the internal stream - void loadFromFile(const std::string &fileName); - - template - static size_t get_size(const T &obj); - - template - static size_t get_size(const std::vector &obj); - - template - static size_t get_size(const std::set &obj); - - template - static size_t get_size(const std::multiset &obj); - - static size_t get_size(const DenseMatrix &obj); - static size_t get_size(const DenseVector &obj); - static size_t get_size(const SparseMatrix &obj); - static size_t get_size(const SparseVector &obj); - - static size_t get_size(const DataPoint &obj); - static size_t get_size(const DataTable &obj); - static size_t get_size(const BSpline &obj); - static size_t get_size(const BSplineBasis &obj); - static size_t get_size(const BSplineBasis1D &obj); - -protected: - template - void _serialize(const T &obj); - - template - void _serialize(const std::vector &obj); - - template - void _serialize(const std::set &obj); - - template - void _serialize(const std::multiset &obj); - - void _serialize(const DenseMatrix &obj); - void _serialize(const DenseVector &obj); - void _serialize(const SparseMatrix &obj); - void _serialize(const SparseVector &obj); - - void _serialize(const DataPoint &obj); - void _serialize(const DataTable &obj); - void _serialize(const BSpline &obj); - void _serialize(const BSplineBasis &obj); - void _serialize(const BSplineBasis1D &obj); - - typedef std::vector StreamType; - StreamType stream; - - // Where we are when serializing - StreamType::iterator write; - - // Where we are when deserializing - StreamType::const_iterator read; - -}; - - -template -void Serializer::serialize(const T &obj) -{ - // We can't set write to stream.end() here because the call - // to stream.resize() below may invalidate iterators - int writeIndex = stream.size(); - - // Increase the size of the stream so it can hold the object - stream.resize(stream.size() + get_size(obj)); - - write = stream.begin() + writeIndex; - - _serialize(obj); -} - -template -void Serializer::_serialize(const T &obj) -{ - // This should really be used to avoid simply copying complex objects that are not trivially copyable - // std::is_trivially_copyable is shipped with GCC 5 -// static_assert(std::is_trivially_copyable::value, "Missing Serializer::_serialize overload for T = "/* __PRETTY_FUNCTION__*/); - - // Get a uint8_t pointer to the object, so we can copy it into the stream - auto objPtr = reinterpret_cast(&obj); - - std::copy(objPtr, objPtr + sizeof(T), write); - - write += sizeof(T); -} - -template -void Serializer::deserialize(T &obj) -{ - // This should really be used to avoid simply copying complex objects that are not trivially copyable - // std::is_trivially_copyable is shipped with GCC 5 -// static_assert(std::is_trivially_copyable::value, "Missing Serializer::deserialize overload for T = "/* __PRETTY_FUNCTION__*/); - - if (read + sizeof(T) > stream.cend()) { - throw Exception("Serializer::deserialize: Stream is missing bytes!"); - } - - auto objPtr = reinterpret_cast(&obj); - - // Copy the data into val - std::copy(read, read + sizeof(T), objPtr); - - read += sizeof(T); -} - -template -size_t Serializer::get_size(const T &obj) -{ - // This should really be used to avoid simply copying complex objects that are not trivially copyable - // std::is_trivially_copyable is shipped with GCC 5 -// static_assert(std::is_trivially_copyable::value, "Missing Serializer::get_size overload for T = "/* __PRETTY_FUNCTION__*/); - - return sizeof(T); -} - -/* - * get_size specializations - */ -template -size_t Serializer::get_size(const std::vector &obj) -{ - size_t size = sizeof(size_t); - for(auto &elem : obj) { - size += get_size(elem); - } - - return size; -} - -template -size_t Serializer::get_size(const std::set &obj) -{ - size_t size = sizeof(size_t); - for(auto &elem : obj) { - size += get_size(elem); - } - - return size; -} - -template -size_t Serializer::get_size(const std::multiset &obj) { - size_t size = sizeof(size_t); - for (auto &elem : obj) { - size += get_size(elem); - } - - return size; -} - -/* - * _serialize specializations - */ -template -void Serializer::_serialize(const std::vector &obj) -{ - _serialize(obj.size()); - for(auto &elem : obj) - { - _serialize(elem); - } -} - -template -void Serializer::_serialize(const std::set &obj) -{ - _serialize(obj.size()); - for(auto &elem : obj) - { - _serialize(elem); - } -} - -template -void Serializer::_serialize(const std::multiset &obj) -{ - _serialize(obj.size()); - for(auto &elem : obj) - { - _serialize(elem); - } -} - - -/* - * deserialize specializations - */ -template -void Serializer::deserialize(std::vector &obj) -{ - size_t size; deserialize(size); - obj.resize(size); - - for (auto &elem : obj) - { - deserialize(elem); - } -} - -template -void Serializer::deserialize(std::set &obj) -{ - size_t size; deserialize(size); - - T elem; - for(size_t i = 0; i < size; ++i) - { - deserialize(elem); - obj.insert(elem); - } -} - -template -void Serializer::deserialize(std::multiset &obj) -{ - size_t size; deserialize(size); - - T elem; - for (size_t i = 0; i < size; ++i) - { - deserialize(elem); - obj.insert(elem); - } -} - - -} // namespace SPLINTER - -#endif // SPLINTER_SERIALIZER_H diff --git a/splinter/src/Core/Assign.h b/splinter/src/Core/Assign.h deleted file mode 100644 index f481731727..0000000000 --- a/splinter/src/Core/Assign.h +++ /dev/null @@ -1,590 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2007 Michael Olbrich -// Copyright (C) 2006-2010 Benoit Jacob -// 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_ASSIGN_H -#define EIGEN_ASSIGN_H - -namespace Eigen { - -namespace internal { - -/*************************************************************************** -* Part 1 : the logic deciding a strategy for traversal and unrolling * -***************************************************************************/ - -template -struct assign_traits -{ -public: - enum { - DstIsAligned = Derived::Flags & AlignedBit, - DstHasDirectAccess = Derived::Flags & DirectAccessBit, - SrcIsAligned = OtherDerived::Flags & AlignedBit, - JointAlignment = bool(DstIsAligned) && bool(SrcIsAligned) ? Aligned : Unaligned - }; - -private: - enum { - InnerSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::SizeAtCompileTime) - : int(Derived::Flags)&RowMajorBit ? int(Derived::ColsAtCompileTime) - : int(Derived::RowsAtCompileTime), - InnerMaxSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::MaxSizeAtCompileTime) - : int(Derived::Flags)&RowMajorBit ? int(Derived::MaxColsAtCompileTime) - : int(Derived::MaxRowsAtCompileTime), - MaxSizeAtCompileTime = Derived::SizeAtCompileTime, - PacketSize = packet_traits::size - }; - - enum { - StorageOrdersAgree = (int(Derived::IsRowMajor) == int(OtherDerived::IsRowMajor)), - MightVectorize = StorageOrdersAgree - && (int(Derived::Flags) & int(OtherDerived::Flags) & ActualPacketAccessBit), - MayInnerVectorize = MightVectorize && int(InnerSize)!=Dynamic && int(InnerSize)%int(PacketSize)==0 - && int(DstIsAligned) && int(SrcIsAligned), - MayLinearize = StorageOrdersAgree && (int(Derived::Flags) & int(OtherDerived::Flags) & LinearAccessBit), - MayLinearVectorize = MightVectorize && MayLinearize && DstHasDirectAccess - && (DstIsAligned || MaxSizeAtCompileTime == Dynamic), - /* If the destination isn't aligned, we have to do runtime checks and we don't unroll, - so it's only good for large enough sizes. */ - MaySliceVectorize = MightVectorize && DstHasDirectAccess - && (int(InnerMaxSize)==Dynamic || int(InnerMaxSize)>=3*PacketSize) - /* slice vectorization can be slow, so we only want it if the slices are big, which is - indicated by InnerMaxSize rather than InnerSize, think of the case of a dynamic block - in a fixed-size matrix */ - }; - -public: - enum { - Traversal = int(MayInnerVectorize) ? int(InnerVectorizedTraversal) - : int(MayLinearVectorize) ? int(LinearVectorizedTraversal) - : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) - : int(MayLinearize) ? int(LinearTraversal) - : int(DefaultTraversal), - Vectorized = int(Traversal) == InnerVectorizedTraversal - || int(Traversal) == LinearVectorizedTraversal - || int(Traversal) == SliceVectorizedTraversal - }; - -private: - enum { - UnrollingLimit = EIGEN_UNROLLING_LIMIT * (Vectorized ? int(PacketSize) : 1), - MayUnrollCompletely = int(Derived::SizeAtCompileTime) != Dynamic - && int(OtherDerived::CoeffReadCost) != Dynamic - && int(Derived::SizeAtCompileTime) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit), - MayUnrollInner = int(InnerSize) != Dynamic - && int(OtherDerived::CoeffReadCost) != Dynamic - && int(InnerSize) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit) - }; - -public: - enum { - Unrolling = (int(Traversal) == int(InnerVectorizedTraversal) || int(Traversal) == int(DefaultTraversal)) - ? ( - int(MayUnrollCompletely) ? int(CompleteUnrolling) - : int(MayUnrollInner) ? int(InnerUnrolling) - : int(NoUnrolling) - ) - : int(Traversal) == int(LinearVectorizedTraversal) - ? ( bool(MayUnrollCompletely) && bool(DstIsAligned) ? int(CompleteUnrolling) : int(NoUnrolling) ) - : int(Traversal) == int(LinearTraversal) - ? ( bool(MayUnrollCompletely) ? int(CompleteUnrolling) : int(NoUnrolling) ) - : int(NoUnrolling) - }; - -#ifdef EIGEN_DEBUG_ASSIGN - static void debug() - { - EIGEN_DEBUG_VAR(DstIsAligned) - EIGEN_DEBUG_VAR(SrcIsAligned) - EIGEN_DEBUG_VAR(JointAlignment) - EIGEN_DEBUG_VAR(InnerSize) - EIGEN_DEBUG_VAR(InnerMaxSize) - EIGEN_DEBUG_VAR(PacketSize) - EIGEN_DEBUG_VAR(StorageOrdersAgree) - EIGEN_DEBUG_VAR(MightVectorize) - EIGEN_DEBUG_VAR(MayLinearize) - EIGEN_DEBUG_VAR(MayInnerVectorize) - EIGEN_DEBUG_VAR(MayLinearVectorize) - EIGEN_DEBUG_VAR(MaySliceVectorize) - EIGEN_DEBUG_VAR(Traversal) - EIGEN_DEBUG_VAR(UnrollingLimit) - EIGEN_DEBUG_VAR(MayUnrollCompletely) - EIGEN_DEBUG_VAR(MayUnrollInner) - EIGEN_DEBUG_VAR(Unrolling) - } -#endif -}; - -/*************************************************************************** -* Part 2 : meta-unrollers -***************************************************************************/ - -/************************ -*** Default traversal *** -************************/ - -template -struct assign_DefaultTraversal_CompleteUnrolling -{ - enum { - outer = Index / Derived1::InnerSizeAtCompileTime, - inner = Index % Derived1::InnerSizeAtCompileTime - }; - - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - dst.copyCoeffByOuterInner(outer, inner, src); - assign_DefaultTraversal_CompleteUnrolling::run(dst, src); - } -}; - -template -struct assign_DefaultTraversal_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} -}; - -template -struct assign_DefaultTraversal_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, typename Derived1::Index outer) - { - dst.copyCoeffByOuterInner(outer, Index, src); - assign_DefaultTraversal_InnerUnrolling::run(dst, src, outer); - } -}; - -template -struct assign_DefaultTraversal_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, typename Derived1::Index) {} -}; - -/*********************** -*** Linear traversal *** -***********************/ - -template -struct assign_LinearTraversal_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - dst.copyCoeff(Index, src); - assign_LinearTraversal_CompleteUnrolling::run(dst, src); - } -}; - -template -struct assign_LinearTraversal_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} -}; - -/************************** -*** Inner vectorization *** -**************************/ - -template -struct assign_innervec_CompleteUnrolling -{ - enum { - outer = Index / Derived1::InnerSizeAtCompileTime, - inner = Index % Derived1::InnerSizeAtCompileTime, - JointAlignment = assign_traits::JointAlignment - }; - - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - dst.template copyPacketByOuterInner(outer, inner, src); - assign_innervec_CompleteUnrolling::size, Stop>::run(dst, src); - } -}; - -template -struct assign_innervec_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} -}; - -template -struct assign_innervec_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, typename Derived1::Index outer) - { - dst.template copyPacketByOuterInner(outer, Index, src); - assign_innervec_InnerUnrolling::size, Stop>::run(dst, src, outer); - } -}; - -template -struct assign_innervec_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, typename Derived1::Index) {} -}; - -/*************************************************************************** -* Part 3 : implementation of all cases -***************************************************************************/ - -template::Traversal, - int Unrolling = assign_traits::Unrolling, - int Version = Specialized> -struct assign_impl; - -/************************ -*** Default traversal *** -************************/ - -template -struct assign_impl -{ - static inline void run(Derived1 &, const Derived2 &) { } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) - for(Index inner = 0; inner < innerSize; ++inner) - dst.copyCoeffByOuterInner(outer, inner, src); - } -}; - -template -struct assign_impl -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - assign_DefaultTraversal_CompleteUnrolling - ::run(dst, src); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) - assign_DefaultTraversal_InnerUnrolling - ::run(dst, src, outer); - } -}; - -/*********************** -*** Linear traversal *** -***********************/ - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - const Index size = dst.size(); - for(Index i = 0; i < size; ++i) - dst.copyCoeff(i, src); - } -}; - -template -struct assign_impl -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - assign_LinearTraversal_CompleteUnrolling - ::run(dst, src); - } -}; - -/************************** -*** Inner vectorization *** -**************************/ - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - const Index packetSize = packet_traits::size; - for(Index outer = 0; outer < outerSize; ++outer) - for(Index inner = 0; inner < innerSize; inner+=packetSize) - dst.template copyPacketByOuterInner(outer, inner, src); - } -}; - -template -struct assign_impl -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - assign_innervec_CompleteUnrolling - ::run(dst, src); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) - assign_innervec_InnerUnrolling - ::run(dst, src, outer); - } -}; - -/*************************** -*** Linear vectorization *** -***************************/ - -template -struct unaligned_assign_impl -{ - template - static EIGEN_STRONG_INLINE void run(const Derived&, OtherDerived&, typename Derived::Index, typename Derived::Index) {} -}; - -template <> -struct unaligned_assign_impl -{ - // MSVC must not inline this functions. If it does, it fails to optimize the - // packet access path. -#ifdef _MSC_VER - template - static EIGEN_DONT_INLINE void run(const Derived& src, OtherDerived& dst, typename Derived::Index start, typename Derived::Index end) -#else - template - static EIGEN_STRONG_INLINE void run(const Derived& src, OtherDerived& dst, typename Derived::Index start, typename Derived::Index end) -#endif - { - for (typename Derived::Index index = start; index < end; ++index) - dst.copyCoeff(index, src); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - const Index size = dst.size(); - typedef packet_traits PacketTraits; - enum { - packetSize = PacketTraits::size, - dstAlignment = PacketTraits::AlignedOnScalar ? Aligned : int(assign_traits::DstIsAligned) , - srcAlignment = assign_traits::JointAlignment - }; - const Index alignedStart = assign_traits::DstIsAligned ? 0 - : 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); - - for(Index index = alignedStart; index < alignedEnd; index += packetSize) - { - dst.template copyPacket(index, src); - } - - unaligned_assign_impl<>::run(src,dst,alignedEnd,size); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - enum { size = Derived1::SizeAtCompileTime, - packetSize = packet_traits::size, - alignedSize = (size/packetSize)*packetSize }; - - assign_innervec_CompleteUnrolling::run(dst, src); - assign_DefaultTraversal_CompleteUnrolling::run(dst, src); - } -}; - -/************************** -*** Slice vectorization *** -***************************/ - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - typedef typename Derived1::Scalar Scalar; - typedef packet_traits PacketTraits; - enum { - packetSize = PacketTraits::size, - alignable = PacketTraits::AlignedOnScalar, - dstIsAligned = assign_traits::DstIsAligned, - dstAlignment = alignable ? Aligned : int(dstIsAligned), - srcAlignment = assign_traits::JointAlignment - }; - const Scalar *dst_ptr = &dst.coeffRef(0,0); - if((!bool(dstIsAligned)) && (size_t(dst_ptr) % sizeof(Scalar))>0) - { - // the pointer is not aligend-on scalar, so alignment is not possible - return assign_impl::run(dst, src); - } - const Index packetAlignedMask = packetSize - 1; - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - const Index alignedStep = alignable ? (packetSize - dst.outerStride() % packetSize) & packetAlignedMask : 0; - Index alignedStart = ((!alignable) || bool(dstIsAligned)) ? 0 : internal::first_aligned(dst_ptr, innerSize); - - for(Index outer = 0; outer < outerSize; ++outer) - { - const Index alignedEnd = alignedStart + ((innerSize-alignedStart) & ~packetAlignedMask); - // do the non-vectorizable part of the assignment - for(Index inner = 0; inner(outer, inner, src); - - // do the non-vectorizable part of the assignment - for(Index inner = alignedEnd; inner((alignedStart+alignedStep)%packetSize, innerSize); - } - } -}; - -} // end namespace internal - -/*************************************************************************** -* Part 4 : implementation of DenseBase methods -***************************************************************************/ - -template -template -EIGEN_STRONG_INLINE Derived& DenseBase - ::lazyAssign(const DenseBase& other) -{ - enum{ - SameType = internal::is_same::value - }; - - EIGEN_STATIC_ASSERT_LVALUE(Derived) - EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived) - EIGEN_STATIC_ASSERT(SameType,YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - -#ifdef EIGEN_DEBUG_ASSIGN - internal::assign_traits::debug(); -#endif - eigen_assert(rows() == other.rows() && cols() == other.cols()); - internal::assign_impl::Traversal) - : int(InvalidTraversal)>::run(derived(),other.derived()); -#ifndef EIGEN_NO_DEBUG - checkTransposeAliasing(other.derived()); -#endif - return derived(); -} - -namespace internal { - -template::Flags) & EvalBeforeAssigningBit) != 0, - bool NeedToTranspose = ((int(Derived::RowsAtCompileTime) == 1 && int(OtherDerived::ColsAtCompileTime) == 1) - | // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&". - // revert to || as soon as not needed anymore. - (int(Derived::ColsAtCompileTime) == 1 && int(OtherDerived::RowsAtCompileTime) == 1)) - && int(Derived::SizeAtCompileTime) != 1> -struct assign_selector; - -template -struct assign_selector { - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.derived()); } - template - static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { other.evalTo(dst); return dst; } -}; -template -struct assign_selector { - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.eval()); } -}; -template -struct assign_selector { - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose()); } - template - static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { Transpose dstTrans(dst); other.evalTo(dstTrans); return dst; } -}; -template -struct assign_selector { - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose().eval()); } -}; - -} // end namespace internal - -template -template -EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) -{ - return internal::assign_selector::run(derived(), other.derived()); -} - -template -EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) -{ - return internal::assign_selector::run(derived(), other.derived()); -} - -template -EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const MatrixBase& other) -{ - return internal::assign_selector::run(derived(), other.derived()); -} - -template -template -EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const DenseBase& other) -{ - return internal::assign_selector::run(derived(), other.derived()); -} - -template -template -EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const EigenBase& other) -{ - return internal::assign_selector::evalTo(derived(), other.derived()); -} - -template -template -EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const ReturnByValue& other) -{ - return internal::assign_selector::evalTo(derived(), other.derived()); -} - -} // end namespace Eigen - -#endif // EIGEN_ASSIGN_H diff --git a/splinter/src/Core/Assign_MKL.h b/splinter/src/Core/Assign_MKL.h deleted file mode 100644 index 7772951b91..0000000000 --- a/splinter/src/Core/Assign_MKL.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - 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. -#ifndef _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/splinter/src/Core/CoreIterators.h b/splinter/src/Core/CoreIterators.h deleted file mode 100644 index 6da4683d2c..0000000000 --- a/splinter/src/Core/CoreIterators.h +++ /dev/null @@ -1,61 +0,0 @@ -// 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/splinter/src/Core/DenseStorage.h b/splinter/src/Core/DenseStorage.h deleted file mode 100644 index 568493cbae..0000000000 --- a/splinter/src/Core/DenseStorage.h +++ /dev/null @@ -1,434 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2006-2009 Benoit Jacob -// Copyright (C) 2010 Hauke Heibel -// -// 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 - -#ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN EIGEN_DENSE_STORAGE_CTOR_PLUGIN; -#else - #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN -#endif - -namespace Eigen { - -namespace internal { - -struct constructor_without_unaligned_array_assert {}; - -template void check_static_allocation_size() -{ - // if EIGEN_STACK_ALLOCATION_LIMIT is defined to 0, then no limit - #if EIGEN_STACK_ALLOCATION_LIMIT - EIGEN_STATIC_ASSERT(Size * sizeof(T) <= EIGEN_STACK_ALLOCATION_LIMIT, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); - #endif -} - -/** \internal - * Static array. If the MatrixOrArrayOptions require auto-alignment, the array will be automatically aligned: - * to 16 bytes boundary if the total size is a multiple of 16 bytes. - */ -template -struct plain_array -{ - T array[Size]; - - plain_array() - { - check_static_allocation_size(); - } - - plain_array(constructor_without_unaligned_array_assert) - { - check_static_allocation_size(); - } -}; - -#if defined(EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT) - #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) -#elif EIGEN_GNUC_AT_LEAST(4,7) - // GCC 4.7 is too aggressive in its optimizations and remove the alignement test based on the fact the array is declared to be aligned. - // See this bug report: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53900 - // Hiding the origin of the array pointer behind a function argument seems to do the trick even if the function is inlined: - template - EIGEN_ALWAYS_INLINE PtrType eigen_unaligned_array_assert_workaround_gcc47(PtrType array) { return array; } - #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ - eigen_assert((reinterpret_cast(eigen_unaligned_array_assert_workaround_gcc47(array)) & sizemask) == 0 \ - && "this assertion is explained here: " \ - "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ - " **** READ THIS WEB PAGE !!! ****"); -#else - #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ - eigen_assert((reinterpret_cast(array) & sizemask) == 0 \ - && "this assertion is explained here: " \ - "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ - " **** READ THIS WEB PAGE !!! ****"); -#endif - -template -struct plain_array -{ - EIGEN_USER_ALIGN16 T array[Size]; - - plain_array() - { - EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(0xf); - check_static_allocation_size(); - } - - plain_array(constructor_without_unaligned_array_assert) - { - check_static_allocation_size(); - } -}; - -template -struct plain_array -{ - EIGEN_USER_ALIGN16 T array[1]; - plain_array() {} - plain_array(constructor_without_unaligned_array_assert) {} -}; - -} // end namespace internal - -/** \internal - * - * \class DenseStorage - * \ingroup Core_Module - * - * \brief Stores the data of a matrix - * - * This class stores the data of fixed-size, dynamic-size or mixed matrices - * in a way as compact as possible. - * - * \sa Matrix - */ -template class DenseStorage; - -// purely fixed-size matrix -template class DenseStorage -{ - internal::plain_array m_data; - public: - DenseStorage() {} - DenseStorage(internal::constructor_without_unaligned_array_assert) - : m_data(internal::constructor_without_unaligned_array_assert()) {} - DenseStorage(const DenseStorage& other) : m_data(other.m_data) {} - DenseStorage& operator=(const DenseStorage& other) - { - if (this != &other) m_data = other.m_data; - return *this; - } - DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} - void swap(DenseStorage& other) { std::swap(m_data,other.m_data); } - static DenseIndex rows(void) {return _Rows;} - static DenseIndex cols(void) {return _Cols;} - void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} - void resize(DenseIndex,DenseIndex,DenseIndex) {} - const T *data() const { return m_data.array; } - T *data() { return m_data.array; } -}; - -// null matrix -template class DenseStorage -{ - public: - DenseStorage() {} - DenseStorage(internal::constructor_without_unaligned_array_assert) {} - DenseStorage(const DenseStorage&) {} - DenseStorage& operator=(const DenseStorage&) { return *this; } - DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} - void swap(DenseStorage& ) {} - static DenseIndex rows(void) {return _Rows;} - static DenseIndex cols(void) {return _Cols;} - void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} - void resize(DenseIndex,DenseIndex,DenseIndex) {} - const T *data() const { return 0; } - T *data() { return 0; } -}; - -// more specializations for null matrices; these are necessary to resolve ambiguities -template class DenseStorage -: public DenseStorage { }; - -template class DenseStorage -: public DenseStorage { }; - -template class DenseStorage -: public DenseStorage { }; - -// dynamic-size matrix with fixed-size storage -template class DenseStorage -{ - internal::plain_array m_data; - DenseIndex m_rows; - DenseIndex m_cols; - public: - DenseStorage() : m_rows(0), m_cols(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) - : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0), m_cols(0) {} - DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows), m_cols(other.m_cols) {} - DenseStorage& operator=(const DenseStorage& other) - { - if (this != &other) - { - m_data = other.m_data; - m_rows = other.m_rows; - m_cols = other.m_cols; - } - return *this; - } - DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) : m_rows(nbRows), m_cols(nbCols) {} - void swap(DenseStorage& other) - { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } - DenseIndex rows() const {return m_rows;} - DenseIndex cols() const {return m_cols;} - void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; } - void resize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; } - const T *data() const { return m_data.array; } - T *data() { return m_data.array; } -}; - -// dynamic-size matrix with fixed-size storage and fixed width -template class DenseStorage -{ - internal::plain_array m_data; - DenseIndex m_rows; - public: - DenseStorage() : m_rows(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) - : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0) {} - DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows) {} - DenseStorage& operator=(const DenseStorage& other) - { - if (this != &other) - { - m_data = other.m_data; - m_rows = other.m_rows; - } - return *this; - } - DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex) : m_rows(nbRows) {} - void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } - DenseIndex rows(void) const {return m_rows;} - DenseIndex cols(void) const {return _Cols;} - void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; } - void resize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; } - const T *data() const { return m_data.array; } - T *data() { return m_data.array; } -}; - -// dynamic-size matrix with fixed-size storage and fixed height -template class DenseStorage -{ - internal::plain_array m_data; - DenseIndex m_cols; - public: - DenseStorage() : m_cols(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) - : m_data(internal::constructor_without_unaligned_array_assert()), m_cols(0) {} - DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_cols(other.m_cols) {} - DenseStorage& operator=(const DenseStorage& other) - { - if (this != &other) - { - m_data = other.m_data; - m_cols = other.m_cols; - } - return *this; - } - DenseStorage(DenseIndex, DenseIndex, DenseIndex nbCols) : m_cols(nbCols) {} - void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } - DenseIndex rows(void) const {return _Rows;} - DenseIndex cols(void) const {return m_cols;} - void conservativeResize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; } - void resize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; } - const T *data() const { return m_data.array; } - T *data() { return m_data.array; } -}; - -// purely dynamic matrix. -template class DenseStorage -{ - T *m_data; - DenseIndex m_rows; - DenseIndex m_cols; - public: - DenseStorage() : m_data(0), m_rows(0), m_cols(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) - : m_data(0), m_rows(0), m_cols(0) {} - DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) - : m_data(internal::conditional_aligned_new_auto(size)), m_rows(nbRows), m_cols(nbCols) - { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - DenseStorage(DenseStorage&& other) - : m_data(std::move(other.m_data)) - , m_rows(std::move(other.m_rows)) - , m_cols(std::move(other.m_cols)) - { - other.m_data = nullptr; - } - DenseStorage& operator=(DenseStorage&& other) - { - using std::swap; - swap(m_data, other.m_data); - swap(m_rows, other.m_rows); - swap(m_cols, other.m_cols); - return *this; - } -#endif - ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); } - void swap(DenseStorage& other) - { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } - DenseIndex rows(void) const {return m_rows;} - DenseIndex cols(void) const {return m_cols;} - void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) - { - m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*m_cols); - m_rows = nbRows; - m_cols = nbCols; - } - void resize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) - { - if(size != m_rows*m_cols) - { - internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); - if (size) - m_data = internal::conditional_aligned_new_auto(size); - else - m_data = 0; - EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN - } - m_rows = nbRows; - m_cols = nbCols; - } - const T *data() const { return m_data; } - T *data() { return m_data; } - private: - DenseStorage(const DenseStorage&); - DenseStorage& operator=(const DenseStorage&); -}; - -// matrix with dynamic width and fixed height (so that matrix has dynamic size). -template class DenseStorage -{ - T *m_data; - DenseIndex m_cols; - public: - DenseStorage() : m_data(0), m_cols(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {} - DenseStorage(DenseIndex size, DenseIndex, DenseIndex nbCols) : m_data(internal::conditional_aligned_new_auto(size)), m_cols(nbCols) - { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - DenseStorage(DenseStorage&& other) - : m_data(std::move(other.m_data)) - , m_cols(std::move(other.m_cols)) - { - other.m_data = nullptr; - } - DenseStorage& operator=(DenseStorage&& other) - { - using std::swap; - swap(m_data, other.m_data); - swap(m_cols, other.m_cols); - return *this; - } -#endif - ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); } - void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } - static DenseIndex rows(void) {return _Rows;} - DenseIndex cols(void) const {return m_cols;} - void conservativeResize(DenseIndex size, DenseIndex, DenseIndex nbCols) - { - m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, _Rows*m_cols); - m_cols = nbCols; - } - EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex, DenseIndex nbCols) - { - if(size != _Rows*m_cols) - { - internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); - if (size) - m_data = internal::conditional_aligned_new_auto(size); - else - m_data = 0; - EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN - } - m_cols = nbCols; - } - const T *data() const { return m_data; } - T *data() { return m_data; } - private: - DenseStorage(const DenseStorage&); - DenseStorage& operator=(const DenseStorage&); -}; - -// matrix with dynamic height and fixed width (so that matrix has dynamic size). -template class DenseStorage -{ - T *m_data; - DenseIndex m_rows; - public: - DenseStorage() : m_data(0), m_rows(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {} - DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex) : m_data(internal::conditional_aligned_new_auto(size)), m_rows(nbRows) - { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - DenseStorage(DenseStorage&& other) - : m_data(std::move(other.m_data)) - , m_rows(std::move(other.m_rows)) - { - other.m_data = nullptr; - } - DenseStorage& operator=(DenseStorage&& other) - { - using std::swap; - swap(m_data, other.m_data); - swap(m_rows, other.m_rows); - return *this; - } -#endif - ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); } - void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } - DenseIndex rows(void) const {return m_rows;} - static DenseIndex cols(void) {return _Cols;} - void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex) - { - m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*_Cols); - m_rows = nbRows; - } - EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex nbRows, DenseIndex) - { - if(size != m_rows*_Cols) - { - internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); - if (size) - m_data = internal::conditional_aligned_new_auto(size); - else - m_data = 0; - EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN - } - m_rows = nbRows; - } - const T *data() const { return m_data; } - T *data() { return m_data; } - private: - DenseStorage(const DenseStorage&); - DenseStorage& operator=(const DenseStorage&); -}; - -} // end namespace Eigen - -#endif // EIGEN_MATRIX_H diff --git a/splinter/src/Core/DiagonalProduct.h b/splinter/src/Core/DiagonalProduct.h deleted file mode 100644 index cc6b536e19..0000000000 --- a/splinter/src/Core/DiagonalProduct.h +++ /dev/null @@ -1,131 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2007-2009 Benoit Jacob -// -// 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 > - : traits -{ - typedef typename scalar_product_traits::ReturnType Scalar; - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime, - MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - - _StorageOrder = MatrixType::Flags & RowMajorBit ? RowMajor : ColMajor, - _ScalarAccessOnDiag = !((int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheLeft) - ||(int(_StorageOrder) == RowMajor && int(ProductOrder) == OnTheRight)), - _SameTypes = is_same::value, - // FIXME currently we need same types, but in the future the next rule should be the one - //_Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && ((!_PacketOnDiag) || (_SameTypes && bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), - _Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), - _LinearAccessMask = (RowsAtCompileTime==1 || ColsAtCompileTime==1) ? LinearAccessBit : 0, - - Flags = ((HereditaryBits|_LinearAccessMask|AlignedBit) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0),//(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit), - Cost0 = EIGEN_ADD_COST(NumTraits::MulCost, MatrixType::CoeffReadCost), - CoeffReadCost = EIGEN_ADD_COST(Cost0,DiagonalType::DiagonalVectorType::CoeffReadCost) - }; -}; -} - -template -class DiagonalProduct : internal::no_assignment_operator, - public MatrixBase > -{ - public: - - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(DiagonalProduct) - - inline DiagonalProduct(const MatrixType& matrix, const DiagonalType& diagonal) - : m_matrix(matrix), m_diagonal(diagonal) - { - eigen_assert(diagonal.diagonal().size() == (ProductOrder == OnTheLeft ? matrix.rows() : matrix.cols())); - } - - EIGEN_STRONG_INLINE Index rows() const { return m_matrix.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_matrix.cols(); } - - EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const - { - return m_diagonal.diagonal().coeff(ProductOrder == OnTheLeft ? row : col) * m_matrix.coeff(row, col); - } - - EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const - { - enum { - StorageOrder = int(MatrixType::Flags) & RowMajorBit ? RowMajor : ColMajor - }; - return coeff(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const - { - enum { - StorageOrder = Flags & RowMajorBit ? RowMajor : ColMajor - }; - const Index indexInDiagonalVector = ProductOrder == OnTheLeft ? row : col; - return packet_impl(row,col,indexInDiagonalVector,typename internal::conditional< - ((int(StorageOrder) == RowMajor && int(ProductOrder) == OnTheLeft) - ||(int(StorageOrder) == ColMajor && int(ProductOrder) == OnTheRight)), internal::true_type, internal::false_type>::type()); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index idx) const - { - enum { - StorageOrder = int(MatrixType::Flags) & RowMajorBit ? RowMajor : ColMajor - }; - return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); - } - - protected: - template - EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::true_type) const - { - return internal::pmul(m_matrix.template packet(row, col), - internal::pset1(m_diagonal.diagonal().coeff(id))); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::false_type) const - { - enum { - InnerSize = (MatrixType::Flags & RowMajorBit) ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime, - DiagonalVectorPacketLoadMode = (LoadMode == Aligned && (((InnerSize%16) == 0) || (int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit)==AlignedBit) ? Aligned : Unaligned) - }; - return internal::pmul(m_matrix.template packet(row, col), - m_diagonal.diagonal().template packet(id)); - } - - typename MatrixType::Nested m_matrix; - typename DiagonalType::Nested m_diagonal; -}; - -/** \returns the diagonal matrix product of \c *this by the diagonal matrix \a diagonal. - */ -template -template -inline const DiagonalProduct -MatrixBase::operator*(const DiagonalBase &a_diagonal) const -{ - return DiagonalProduct(derived(), a_diagonal.derived()); -} - -} // end namespace Eigen - -#endif // EIGEN_DIAGONALPRODUCT_H diff --git a/splinter/src/Core/Flagged.h b/splinter/src/Core/Flagged.h deleted file mode 100644 index 1f2955fc1d..0000000000 --- a/splinter/src/Core/Flagged.h +++ /dev/null @@ -1,140 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Benoit Jacob -// -// 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 - * - * \brief Expression with modified flags - * - * \param ExpressionType the type of the object of which we are modifying the flags - * \param Added the flags added to the expression - * \param Removed the flags removed from the expression (has priority over Added). - * - * This class represents an expression whose flags have been modified. - * It is the return type of MatrixBase::flagged() - * and most of the time this is the only way it is used. - * - * \sa MatrixBase::flagged() - */ - -namespace internal { -template -struct traits > : traits -{ - enum { Flags = (ExpressionType::Flags | Added) & ~Removed }; -}; -} - -template class Flagged - : public MatrixBase > -{ - public: - - typedef MatrixBase Base; - - EIGEN_DENSE_PUBLIC_INTERFACE(Flagged) - typedef typename internal::conditional::ret, - ExpressionType, const ExpressionType&>::type ExpressionTypeNested; - typedef typename ExpressionType::InnerIterator InnerIterator; - - inline Flagged(const ExpressionType& matrix) : m_matrix(matrix) {} - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - inline Index outerStride() const { return m_matrix.outerStride(); } - inline Index innerStride() const { return m_matrix.innerStride(); } - - inline CoeffReturnType coeff(Index row, Index col) const - { - return m_matrix.coeff(row, col); - } - - inline CoeffReturnType coeff(Index index) const - { - return m_matrix.coeff(index); - } - - inline const Scalar& coeffRef(Index row, Index col) const - { - return m_matrix.const_cast_derived().coeffRef(row, col); - } - - inline const Scalar& coeffRef(Index index) const - { - return m_matrix.const_cast_derived().coeffRef(index); - } - - inline Scalar& coeffRef(Index row, Index col) - { - return m_matrix.const_cast_derived().coeffRef(row, col); - } - - inline Scalar& coeffRef(Index index) - { - return m_matrix.const_cast_derived().coeffRef(index); - } - - template - inline const PacketScalar packet(Index row, Index col) const - { - return m_matrix.template packet(row, col); - } - - template - inline void writePacket(Index row, Index col, const PacketScalar& x) - { - m_matrix.const_cast_derived().template writePacket(row, col, x); - } - - template - inline const PacketScalar packet(Index index) const - { - return m_matrix.template packet(index); - } - - template - inline void writePacket(Index index, const PacketScalar& x) - { - m_matrix.const_cast_derived().template writePacket(index, x); - } - - const ExpressionType& _expression() const { return m_matrix; } - - template - typename ExpressionType::PlainObject solveTriangular(const MatrixBase& other) const; - - template - void solveTriangularInPlace(const MatrixBase& other) const; - - protected: - ExpressionTypeNested m_matrix; -}; - -/** \returns an expression of *this with added and removed flags - * - * This is mostly for internal use. - * - * \sa class Flagged - */ -template -template -inline const Flagged -DenseBase::flagged() const -{ - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_FLAGGED_H diff --git a/splinter/src/Core/Functors.h b/splinter/src/Core/Functors.h deleted file mode 100644 index 5f14c6587e..0000000000 --- a/splinter/src/Core/Functors.h +++ /dev/null @@ -1,1026 +0,0 @@ -// 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_FUNCTORS_H -#define EIGEN_FUNCTORS_H - -namespace Eigen { - -namespace internal { - -// associative functors: - -/** \internal - * \brief Template functor to compute the sum of two scalars - * - * \sa class CwiseBinaryOp, MatrixBase::operator+, class VectorwiseOp, MatrixBase::sum() - */ -template struct scalar_sum_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_sum_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return a + b; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::padd(a,b); } - template - EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const - { return internal::predux(a); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasAdd - }; -}; - -/** \internal - * \brief Template functor to compute the product of two scalars - * - * \sa class CwiseBinaryOp, Cwise::operator*(), class VectorwiseOp, MatrixBase::redux() - */ -template struct scalar_product_op { - enum { - // TODO vectorize mixed product - Vectorizable = is_same::value && packet_traits::HasMul && packet_traits::HasMul - }; - typedef typename scalar_product_traits::ReturnType result_type; - EIGEN_EMPTY_STRUCT_CTOR(scalar_product_op) - EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a * b; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pmul(a,b); } - template - EIGEN_STRONG_INLINE const result_type predux(const Packet& a) const - { return internal::predux_mul(a); } -}; -template -struct functor_traits > { - enum { - Cost = (NumTraits::MulCost + NumTraits::MulCost)/2, // rough estimate! - PacketAccess = scalar_product_op::Vectorizable - }; -}; - -/** \internal - * \brief Template functor to compute the conjugate product of two scalars - * - * This is a short cut for conj(x) * y which is needed for optimization purpose; in Eigen2 support mode, this becomes x * conj(y) - */ -template struct scalar_conj_product_op { - - enum { - Conj = NumTraits::IsComplex - }; - - typedef typename scalar_product_traits::ReturnType result_type; - - EIGEN_EMPTY_STRUCT_CTOR(scalar_conj_product_op) - EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const - { return conj_helper().pmul(a,b); } - - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return conj_helper().pmul(a,b); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::MulCost, - PacketAccess = internal::is_same::value && packet_traits::HasMul - }; -}; - -/** \internal - * \brief Template functor to compute the min of two scalars - * - * \sa class CwiseBinaryOp, MatrixBase::cwiseMin, class VectorwiseOp, MatrixBase::minCoeff() - */ -template struct scalar_min_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_min_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { using std::min; return (min)(a, b); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pmin(a,b); } - template - EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const - { return internal::predux_min(a); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasMin - }; -}; - -/** \internal - * \brief Template functor to compute the max of two scalars - * - * \sa class CwiseBinaryOp, MatrixBase::cwiseMax, class VectorwiseOp, MatrixBase::maxCoeff() - */ -template struct scalar_max_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_max_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { using std::max; return (max)(a, b); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pmax(a,b); } - template - EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const - { return internal::predux_max(a); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasMax - }; -}; - -/** \internal - * \brief Template functor to compute the hypot of two scalars - * - * \sa MatrixBase::stableNorm(), class Redux - */ -template struct scalar_hypot_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_hypot_op) -// typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& _x, const Scalar& _y) const - { - using std::max; - using std::min; - using std::sqrt; - Scalar p = (max)(_x, _y); - Scalar q = (min)(_x, _y); - Scalar qp = q/p; - return p * sqrt(Scalar(1) + qp*qp); - } -}; -template -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 numext::pow(a, b); } -}; -template -struct functor_traits > { - enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; -}; - -// other binary functors: - -/** \internal - * \brief Template functor to compute the difference of two scalars - * - * \sa class CwiseBinaryOp, MatrixBase::operator- - */ -template struct scalar_difference_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_difference_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return a - b; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::psub(a,b); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasSub - }; -}; - -/** \internal - * \brief Template functor to compute the quotient of two scalars - * - * \sa class CwiseBinaryOp, Cwise::operator/() - */ -template struct scalar_quotient_op { - enum { - // TODO vectorize mixed product - Vectorizable = is_same::value && packet_traits::HasDiv && packet_traits::HasDiv - }; - typedef typename scalar_product_traits::ReturnType result_type; - EIGEN_EMPTY_STRUCT_CTOR(scalar_quotient_op) - EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a / b; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pdiv(a,b); } -}; -template -struct functor_traits > { - enum { - Cost = (NumTraits::MulCost + NumTraits::MulCost), // rough estimate! - PacketAccess = scalar_quotient_op::Vectorizable - }; -}; - - - -/** \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 - }; -}; - -/** \internal - * \brief Template functors for comparison of two scalars - * \todo Implement packet-comparisons - */ -template struct scalar_cmp_op; - -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = false - }; -}; - -template -struct result_of(Scalar,Scalar)> { - typedef bool type; -}; - - -template struct scalar_cmp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) - EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a==b;} -}; -template struct scalar_cmp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) - EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a struct scalar_cmp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) - EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a<=b;} -}; -template struct scalar_cmp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) - EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return !(a<=b || b<=a);} -}; -template struct scalar_cmp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) - EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a!=b;} -}; - -// unary functors: - -/** \internal - * \brief Template functor to compute the opposite of a scalar - * - * \sa class CwiseUnaryOp, MatrixBase::operator- - */ -template struct scalar_opposite_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_opposite_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return -a; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pnegate(a); } -}; -template -struct functor_traits > -{ enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasNegate }; -}; - -/** \internal - * \brief Template functor to compute the absolute value of a scalar - * - * \sa class CwiseUnaryOp, Cwise::abs - */ -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 { using std::abs; return abs(a); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pabs(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasAbs - }; -}; - -/** \internal - * \brief Template functor to compute the squared absolute value of a scalar - * - * \sa class CwiseUnaryOp, Cwise::abs2 - */ -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 numext::abs2(a); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pmul(a,a); } -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasAbs2 }; }; - -/** \internal - * \brief Template functor to compute the conjugate of a complex value - * - * \sa class CwiseUnaryOp, MatrixBase::conjugate() - */ -template struct scalar_conjugate_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_conjugate_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { using numext::conj; return conj(a); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pconj(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = NumTraits::IsComplex ? NumTraits::AddCost : 0, - PacketAccess = packet_traits::HasConj - }; -}; - -/** \internal - * \brief Template functor to cast a scalar to another type - * - * \sa class CwiseUnaryOp, MatrixBase::cast() - */ -template -struct scalar_cast_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cast_op) - typedef NewType result_type; - EIGEN_STRONG_INLINE const NewType operator() (const Scalar& a) const { return cast(a); } -}; -template -struct functor_traits > -{ enum { Cost = is_same::value ? 0 : NumTraits::AddCost, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to extract the real part of a complex - * - * \sa class CwiseUnaryOp, MatrixBase::real() - */ -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 numext::real(a); } -}; -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to extract the imaginary part of a complex - * - * \sa class CwiseUnaryOp, MatrixBase::imag() - */ -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 numext::imag(a); } -}; -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to extract the real part of a complex as a reference - * - * \sa class CwiseUnaryOp, MatrixBase::real() - */ -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 numext::real_ref(*const_cast(&a)); } -}; -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to extract the imaginary part of a complex as a reference - * - * \sa class CwiseUnaryOp, MatrixBase::imag() - */ -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 numext::imag_ref(*const_cast(&a)); } -}; -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -/** \internal - * - * \brief Template functor to compute the exponential of a scalar - * - * \sa class CwiseUnaryOp, Cwise::exp() - */ -template struct scalar_exp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_exp_op) - inline const Scalar operator() (const Scalar& a) const { using std::exp; return exp(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::pexp(a); } -}; -template -struct functor_traits > -{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasExp }; }; - -/** \internal - * - * \brief Template functor to compute the logarithm of a scalar - * - * \sa class CwiseUnaryOp, Cwise::log() - */ -template struct scalar_log_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_log_op) - inline const Scalar operator() (const Scalar& a) const { using std::log; return log(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::plog(a); } -}; -template -struct functor_traits > -{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasLog }; }; - -/** \internal - * \brief Template functor to multiply a scalar by a fixed other one - * - * \sa class CwiseUnaryOp, MatrixBase::operator*, MatrixBase::operator/ - */ -/* NOTE why doing the pset1() in packetOp *is* an optimization ? - * indeed it seems better to declare m_other as a Packet and do the pset1() once - * in the constructor. However, in practice: - * - GCC does not like m_other as a Packet and generate a load every time it needs it - * - on the other hand GCC is able to moves the pset1() outside the loop :) - * - simpler code ;) - * (ICC and gcc 4.4 seems to perform well in both cases, the issue is visible with y = a*x + b*y) - */ -template -struct scalar_multiple_op { - typedef typename packet_traits::type Packet; - // FIXME default copy constructors seems bugged with std::complex<> - EIGEN_STRONG_INLINE scalar_multiple_op(const scalar_multiple_op& other) : m_other(other.m_other) { } - EIGEN_STRONG_INLINE scalar_multiple_op(const Scalar& other) : m_other(other) { } - EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a * m_other; } - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pmul(a, pset1(m_other)); } - typename add_const_on_value_type::Nested>::type m_other; -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; - -template -struct scalar_multiple2_op { - typedef typename scalar_product_traits::ReturnType result_type; - EIGEN_STRONG_INLINE scalar_multiple2_op(const scalar_multiple2_op& other) : m_other(other.m_other) { } - EIGEN_STRONG_INLINE scalar_multiple2_op(const Scalar2& other) : m_other(other) { } - EIGEN_STRONG_INLINE result_type operator() (const Scalar1& a) const { return a * m_other; } - typename add_const_on_value_type::Nested>::type m_other; -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to divide a scalar by a fixed other one - * - * This functor is used to implement the quotient of a matrix by - * a scalar where the scalar type is not necessarily a floating point type. - * - * \sa class CwiseUnaryOp, MatrixBase::operator/ - */ -template -struct scalar_quotient1_op { - typedef typename packet_traits::type Packet; - // FIXME default copy constructors seems bugged with std::complex<> - EIGEN_STRONG_INLINE scalar_quotient1_op(const scalar_quotient1_op& other) : m_other(other.m_other) { } - EIGEN_STRONG_INLINE scalar_quotient1_op(const Scalar& other) : m_other(other) {} - EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a / m_other; } - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pdiv(a, pset1(m_other)); } - typename add_const_on_value_type::Nested>::type m_other; -}; -template -struct functor_traits > -{ enum { Cost = 2 * NumTraits::MulCost, PacketAccess = packet_traits::HasDiv }; }; - -// nullary functors - -template -struct scalar_constant_op { - typedef typename packet_traits::type Packet; - EIGEN_STRONG_INLINE scalar_constant_op(const scalar_constant_op& other) : m_other(other.m_other) { } - EIGEN_STRONG_INLINE scalar_constant_op(const Scalar& other) : m_other(other) { } - template - EIGEN_STRONG_INLINE const Scalar operator() (Index, Index = 0) const { return m_other; } - template - EIGEN_STRONG_INLINE const Packet packetOp(Index, Index = 0) const { return internal::pset1(m_other); } - const Scalar m_other; -}; -template -struct functor_traits > -// FIXME replace this packet test by a safe one -{ enum { Cost = 1, PacketAccess = packet_traits::Vectorizable, IsRepeatable = true }; }; - -template struct scalar_identity_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_identity_op) - template - EIGEN_STRONG_INLINE const Scalar operator() (Index row, Index col) const { return row==col ? Scalar(1) : Scalar(0); } -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = false, IsRepeatable = true }; }; - -template struct linspaced_op_impl; - -// linear access for packet ops: -// 1) initialization -// base = [low, ..., low] + ([step, ..., step] * [-size, ..., 0]) -// 2) each step (where size is 1 for coeff access or PacketSize for packet access) -// base += [size*step, ..., size*step] -// -// TODO: Perhaps it's better to initialize lazily (so not in the constructor but in packetOp) -// in order to avoid the padd() in operator() ? -template -struct linspaced_op_impl -{ - typedef typename packet_traits::type Packet; - - linspaced_op_impl(const Scalar& low, const Scalar& step) : - m_low(low), m_step(step), - m_packetStep(pset1(packet_traits::size*step)), - m_base(padd(pset1(low), pmul(pset1(step),plset(-packet_traits::size)))) {} - - template - EIGEN_STRONG_INLINE const Scalar operator() (Index i) const - { - m_base = padd(m_base, pset1(m_step)); - return m_low+Scalar(i)*m_step; - } - - template - EIGEN_STRONG_INLINE const Packet packetOp(Index) const { return m_base = padd(m_base,m_packetStep); } - - const Scalar m_low; - const Scalar m_step; - const Packet m_packetStep; - mutable Packet m_base; -}; - -// random access for packet ops: -// 1) each step -// [low, ..., low] + ( [step, ..., step] * ( [i, ..., i] + [0, ..., size] ) ) -template -struct linspaced_op_impl -{ - typedef typename packet_traits::type Packet; - - linspaced_op_impl(const Scalar& low, const Scalar& step) : - m_low(low), m_step(step), - m_lowPacket(pset1(m_low)), m_stepPacket(pset1(m_step)), m_interPacket(plset(0)) {} - - template - EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return m_low+i*m_step; } - - template - EIGEN_STRONG_INLINE const Packet packetOp(Index i) const - { return internal::padd(m_lowPacket, pmul(m_stepPacket, padd(pset1(Scalar(i)),m_interPacket))); } - - const Scalar m_low; - const Scalar m_step; - const Packet m_lowPacket; - const Packet m_stepPacket; - const Packet m_interPacket; -}; - -// ----- Linspace functor ---------------------------------------------------------------- - -// Forward declaration (we default to random access which does not really give -// us a speed gain when using packet access but it allows to use the functor in -// nested expressions). -template struct linspaced_op; -template struct functor_traits< linspaced_op > -{ enum { Cost = 1, PacketAccess = packet_traits::HasSetLinear, IsRepeatable = true }; }; -template struct linspaced_op -{ - typedef typename packet_traits::type Packet; - linspaced_op(const Scalar& low, const Scalar& high, DenseIndex num_steps) : impl((num_steps==1 ? high : low), (num_steps==1 ? Scalar() : (high-low)/Scalar(num_steps-1))) {} - - template - EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return impl(i); } - - // We need this function when assigning e.g. a RowVectorXd to a MatrixXd since - // there row==0 and col is used for the actual iteration. - template - EIGEN_STRONG_INLINE const Scalar operator() (Index row, Index col) const - { - eigen_assert(col==0 || row==0); - return impl(col + row); - } - - template - EIGEN_STRONG_INLINE const Packet packetOp(Index i) const { return impl.packetOp(i); } - - // We need this function when assigning e.g. a RowVectorXd to a MatrixXd since - // there row==0 and col is used for the actual iteration. - template - EIGEN_STRONG_INLINE const Packet packetOp(Index row, Index col) const - { - eigen_assert(col==0 || row==0); - return impl.packetOp(col + row); - } - - // This proxy object handles the actual required temporaries, the different - // implementations (random vs. sequential access) as well as the - // correct piping to size 2/4 packet operations. - const linspaced_op_impl impl; -}; - -// all functors allow linear access, except scalar_identity_op. So we fix here a quick meta -// to indicate whether a functor allows linear access, just always answering 'yes' except for -// scalar_identity_op. -// FIXME move this to functor_traits adding a functor_default -template struct functor_has_linear_access { enum { ret = 1 }; }; -template struct functor_has_linear_access > { enum { ret = 0 }; }; - -// In Eigen, any binary op (Product, CwiseBinaryOp) require the Lhs and Rhs to have the same scalar type, except for multiplication -// where the mixing of different types is handled by scalar_product_traits -// In particular, real * complex is allowed. -// FIXME move this to functor_traits adding a functor_default -template struct functor_is_product_like { enum { ret = 0 }; }; -template struct functor_is_product_like > { enum { ret = 1 }; }; -template struct functor_is_product_like > { enum { ret = 1 }; }; -template struct functor_is_product_like > { enum { ret = 1 }; }; - - -/** \internal - * \brief Template functor to add a scalar to a fixed other one - * \sa class CwiseUnaryOp, Array::operator+ - */ -/* If you wonder why doing the pset1() in packetOp() is an optimization check scalar_multiple_op */ -template -struct scalar_add_op { - typedef typename packet_traits::type Packet; - // FIXME default copy constructors seems bugged with std::complex<> - inline scalar_add_op(const scalar_add_op& other) : m_other(other.m_other) { } - inline scalar_add_op(const Scalar& other) : m_other(other) { } - inline Scalar operator() (const Scalar& a) const { return a + m_other; } - inline const Packet packetOp(const Packet& a) const - { return internal::padd(a, pset1(m_other)); } - const Scalar m_other; -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasAdd }; }; - -/** \internal - * \brief Template functor to compute the square root of a scalar - * \sa class CwiseUnaryOp, Cwise::sqrt() - */ -template struct scalar_sqrt_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_sqrt_op) - inline const Scalar operator() (const Scalar& a) const { using std::sqrt; return sqrt(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::psqrt(a); } -}; -template -struct functor_traits > -{ enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasSqrt - }; -}; - -/** \internal - * \brief Template functor to compute the cosine of a scalar - * \sa class CwiseUnaryOp, ArrayBase::cos() - */ -template struct scalar_cos_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cos_op) - inline Scalar operator() (const Scalar& a) const { using std::cos; return cos(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::pcos(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasCos - }; -}; - -/** \internal - * \brief Template functor to compute the sine of a scalar - * \sa class CwiseUnaryOp, ArrayBase::sin() - */ -template struct scalar_sin_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_sin_op) - inline const Scalar operator() (const Scalar& a) const { using std::sin; return sin(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::psin(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasSin - }; -}; - - -/** \internal - * \brief Template functor to compute the tan of a scalar - * \sa class CwiseUnaryOp, ArrayBase::tan() - */ -template struct scalar_tan_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_tan_op) - inline const Scalar operator() (const Scalar& a) const { using std::tan; return tan(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::ptan(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasTan - }; -}; - -/** \internal - * \brief Template functor to compute the arc cosine of a scalar - * \sa class CwiseUnaryOp, ArrayBase::acos() - */ -template struct scalar_acos_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_acos_op) - inline const Scalar operator() (const Scalar& a) const { using std::acos; return acos(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::pacos(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasACos - }; -}; - -/** \internal - * \brief Template functor to compute the arc sine of a scalar - * \sa class CwiseUnaryOp, ArrayBase::asin() - */ -template struct scalar_asin_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_asin_op) - inline const Scalar operator() (const Scalar& a) const { using std::asin; return asin(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::pasin(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasASin - }; -}; - -/** \internal - * \brief Template functor to raise a scalar to a power - * \sa class CwiseUnaryOp, Cwise::pow - */ -template -struct scalar_pow_op { - // FIXME default copy constructors seems bugged with std::complex<> - inline scalar_pow_op(const scalar_pow_op& other) : m_exponent(other.m_exponent) { } - inline scalar_pow_op(const Scalar& exponent) : m_exponent(exponent) {} - inline Scalar operator() (const Scalar& a) const { return numext::pow(a, m_exponent); } - const Scalar m_exponent; -}; -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() - */ -template -struct scalar_inverse_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_inverse_op) - inline Scalar operator() (const Scalar& a) const { return Scalar(1)/a; } - template - inline const Packet packetOp(const Packet& a) const - { return internal::pdiv(pset1(Scalar(1)),a); } -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasDiv }; }; - -/** \internal - * \brief Template functor to compute the square of a scalar - * \sa class CwiseUnaryOp, Cwise::square() - */ -template -struct scalar_square_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_square_op) - inline Scalar operator() (const Scalar& a) const { return a*a; } - template - inline const Packet packetOp(const Packet& a) const - { return internal::pmul(a,a); } -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; - -/** \internal - * \brief Template functor to compute the cube of a scalar - * \sa class CwiseUnaryOp, Cwise::cube() - */ -template -struct scalar_cube_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cube_op) - inline Scalar operator() (const Scalar& a) const { return a*a*a; } - template - inline const Packet packetOp(const Packet& a) const - { return internal::pmul(a,pmul(a,a)); } -}; -template -struct functor_traits > -{ enum { Cost = 2*NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; - -// default functor traits for STL functors: - -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = functor_traits::Cost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = functor_traits::Cost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1 + functor_traits::Cost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1 + functor_traits::Cost, PacketAccess = false }; }; - -#ifdef EIGEN_STDEXT_SUPPORT - -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -template -struct functor_traits > > -{ enum { Cost = 0, PacketAccess = false }; }; - -template -struct functor_traits > > -{ enum { Cost = 0, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = functor_traits::Cost + functor_traits::Cost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = functor_traits::Cost + functor_traits::Cost + functor_traits::Cost, PacketAccess = false }; }; - -#endif // EIGEN_STDEXT_SUPPORT - -// allow to add new functors and specializations of functor_traits from outside Eigen. -// this macro is really needed because functor_traits must be specialized after it is declared but before it is used... -#ifdef EIGEN_FUNCTORS_PLUGIN -#include EIGEN_FUNCTORS_PLUGIN -#endif - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_FUNCTORS_H diff --git a/splinter/src/Core/GeneralProduct.h b/splinter/src/Core/GeneralProduct.h deleted file mode 100644 index 29ac522d2e..0000000000 --- a/splinter/src/Core/GeneralProduct.h +++ /dev/null @@ -1,638 +0,0 @@ -// 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 { - -// Column major -template -EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& dest, const Func& func, const false_type&) -{ - 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 -EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& dest, const Func& func, const true_type&) { - 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 -struct traits > - : traits, Lhs, Rhs> > -{}; - -} - -template -class GeneralProduct - : public ProductBase, Lhs, Rhs> -{ - template struct is_row_major : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {}; - - 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) - } - - struct set { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() = src; } }; - struct add { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() += src; } }; - struct sub { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() -= src; } }; - struct adds { - Scalar m_scale; - adds(const Scalar& s) : m_scale(s) {} - template void operator()(const Dst& dst, const Src& src) const { - dst.const_cast_derived() += m_scale * src; - } - }; - - template - inline void evalTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, set(), is_row_major()); - } - - template - inline void addTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, add(), is_row_major()); - } - - template - inline void subTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, sub(), is_row_major()); - } - - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const - { - internal::outer_product_selector_run(*this, dest, adds(alpha), is_row_major()); - } -}; - -/*********************************************************************** -* Implementation of General Matrix Vector Product -***********************************************************************/ - -/* According to the shape/flags of the matrix we have to distinghish 3 different cases: - * 1 - the matrix is col-major, BLAS compatible and M is large => 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& a_lhs, const Rhs& a_rhs) : Base(a_lhs,a_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, const 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, const 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, const 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()); - - // make sure Dest is a compile-time vector type (bug 1166) - typedef typename conditional::type ActualDest; - - 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 = (ActualDest::InnerStrideAtCompileTime==1), - ComplexByReal = (NumTraits::IsComplex) && (!NumTraits::IsComplex), - MightCannotUseDest = (ActualDest::InnerStrideAtCompileTime!=1) || ComplexByReal - }; - - gemv_static_vector_if static_dest; - - bool alphaIsCompatible = (!ComplexByReal) || (numext::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, const 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.col(0).innerStride(), //NOTE if dest is not a vector at compile-time, then dest.innerStride() might be wrong. (bug 1166) - actualAlpha); - } -}; - -template<> struct gemv_selector -{ - template - static void run(const ProductType& prod, Dest& dest, const 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, const 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/splinter/src/Core/GenericPacketMath.h b/splinter/src/Core/GenericPacketMath.h deleted file mode 100644 index 5f783ebeee..0000000000 --- a/splinter/src/Core/GenericPacketMath.h +++ /dev/null @@ -1,350 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// 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 - * \file GenericPacketMath.h - * - * Default implementation for types not supported by the vectorization. - * In practice these functions are provided to make easier the writing - * of generic vectorized code. - */ - -#ifndef EIGEN_DEBUG_ALIGNED_LOAD -#define EIGEN_DEBUG_ALIGNED_LOAD -#endif - -#ifndef EIGEN_DEBUG_UNALIGNED_LOAD -#define EIGEN_DEBUG_UNALIGNED_LOAD -#endif - -#ifndef EIGEN_DEBUG_ALIGNED_STORE -#define EIGEN_DEBUG_ALIGNED_STORE -#endif - -#ifndef EIGEN_DEBUG_UNALIGNED_STORE -#define EIGEN_DEBUG_UNALIGNED_STORE -#endif - -struct default_packet_traits -{ - enum { - HasAdd = 1, - HasSub = 1, - HasMul = 1, - HasNegate = 1, - HasAbs = 1, - HasAbs2 = 1, - HasMin = 1, - HasMax = 1, - HasConj = 1, - HasSetLinear = 1, - - HasDiv = 0, - HasSqrt = 0, - HasExp = 0, - HasLog = 0, - HasPow = 0, - - HasSin = 0, - HasCos = 0, - HasTan = 0, - HasASin = 0, - HasACos = 0, - HasATan = 0 - }; -}; - -template struct packet_traits : default_packet_traits -{ - typedef T type; - enum { - Vectorizable = 0, - size = 1, - AlignedOnScalar = 0 - }; - enum { - HasAdd = 0, - HasSub = 0, - HasMul = 0, - HasNegate = 0, - HasAbs = 0, - HasAbs2 = 0, - HasMin = 0, - HasMax = 0, - HasConj = 0, - HasSetLinear = 0 - }; -}; - -/** \internal \returns a + b (coeff-wise) */ -template inline Packet -padd(const Packet& a, - const Packet& b) { return a+b; } - -/** \internal \returns a - b (coeff-wise) */ -template inline Packet -psub(const Packet& a, - const Packet& b) { return a-b; } - -/** \internal \returns -a (coeff-wise) */ -template inline Packet -pnegate(const Packet& a) { return -a; } - -/** \internal \returns conj(a) (coeff-wise) */ -template inline Packet -pconj(const Packet& a) { return numext::conj(a); } - -/** \internal \returns a * b (coeff-wise) */ -template inline Packet -pmul(const Packet& a, - const Packet& b) { return a*b; } - -/** \internal \returns a / b (coeff-wise) */ -template inline Packet -pdiv(const Packet& a, - const Packet& b) { return a/b; } - -/** \internal \returns the min of \a a and \a b (coeff-wise) */ -template inline Packet -pmin(const Packet& a, - const Packet& b) { using std::min; return (min)(a, b); } - -/** \internal \returns the max of \a a and \a b (coeff-wise) */ -template inline Packet -pmax(const Packet& a, - const Packet& b) { using std::max; return (max)(a, b); } - -/** \internal \returns the absolute value of \a a */ -template inline Packet -pabs(const Packet& a) { using std::abs; return abs(a); } - -/** \internal \returns the bitwise and of \a a and \a b */ -template inline Packet -pand(const Packet& a, const Packet& b) { return a & b; } - -/** \internal \returns the bitwise or of \a a and \a b */ -template inline Packet -por(const Packet& a, const Packet& b) { return a | b; } - -/** \internal \returns the bitwise xor of \a a and \a b */ -template inline Packet -pxor(const Packet& a, const Packet& b) { return a ^ b; } - -/** \internal \returns the bitwise andnot of \a a and \a b */ -template inline Packet -pandnot(const Packet& a, const Packet& b) { return a & (!b); } - -/** \internal \returns a packet version of \a *from, from must be 16 bytes aligned */ -template inline Packet -pload(const typename unpacket_traits::type* from) { return *from; } - -/** \internal \returns a packet version of \a *from, (un-aligned load) */ -template inline Packet -ploadu(const typename unpacket_traits::type* from) { return *from; } - -/** \internal \returns a packet with elements of \a *from duplicated. - * For instance, for a packet of 8 elements, 4 scalar will be read from \a *from and - * duplicated to form: {from[0],from[0],from[1],from[1],,from[2],from[2],,from[3],from[3]} - * Currently, this function is only used for scalar * complex products. - */ -template inline Packet -ploaddup(const typename unpacket_traits::type* from) { return *from; } - -/** \internal \returns a packet with constant coefficients \a a, e.g.: (a,a,a,a) */ -template inline Packet -pset1(const typename unpacket_traits::type& a) { return a; } - -/** \internal \brief Returns a packet with coefficients (a,a+1,...,a+packet_size-1). */ -template inline typename packet_traits::type -plset(const Scalar& a) { return a; } - -/** \internal copy the packet \a from to \a *to, \a to must be 16 bytes aligned */ -template inline void pstore(Scalar* to, const Packet& from) -{ (*to) = from; } - -/** \internal copy the packet \a from to \a *to, (un-aligned store) */ -template inline void pstoreu(Scalar* to, const Packet& from) -{ (*to) = from; } - -/** \internal tries to do cache prefetching of \a addr */ -template inline void prefetch(const Scalar* addr) -{ -#if !defined(_MSC_VER) -__builtin_prefetch(addr); -#endif -} - -/** \internal \returns the first element of a packet */ -template inline typename unpacket_traits::type pfirst(const Packet& a) -{ return a; } - -/** \internal \returns a packet where the element i contains the sum of the packet of \a vec[i] */ -template inline Packet -preduxp(const Packet* vecs) { return vecs[0]; } - -/** \internal \returns the sum of the elements of \a a*/ -template inline typename unpacket_traits::type predux(const Packet& a) -{ return a; } - -/** \internal \returns the product of the elements of \a a*/ -template inline typename unpacket_traits::type predux_mul(const Packet& a) -{ return a; } - -/** \internal \returns the min of the elements of \a a*/ -template inline typename unpacket_traits::type predux_min(const Packet& a) -{ return a; } - -/** \internal \returns the max of the elements of \a a*/ -template inline typename unpacket_traits::type predux_max(const Packet& a) -{ return a; } - -/** \internal \returns the reversed elements of \a a*/ -template inline Packet preverse(const Packet& a) -{ return a; } - - -/** \internal \returns \a a with real and imaginary part flipped (for complex type only) */ -template inline Packet pcplxflip(const Packet& a) -{ - // FIXME: uncomment the following in case we drop the internal imag and real functions. -// using std::imag; -// using std::real; - return Packet(imag(a),real(a)); -} - -/************************** -* Special math functions -***************************/ - -/** \internal \returns the sine of \a a (coeff-wise) */ -template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS -Packet psin(const Packet& a) { using std::sin; return sin(a); } - -/** \internal \returns the cosine of \a a (coeff-wise) */ -template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS -Packet pcos(const Packet& a) { using std::cos; return cos(a); } - -/** \internal \returns the tan of \a a (coeff-wise) */ -template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS -Packet ptan(const Packet& a) { using std::tan; return tan(a); } - -/** \internal \returns the arc sine of \a a (coeff-wise) */ -template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS -Packet pasin(const Packet& a) { using std::asin; return asin(a); } - -/** \internal \returns the arc cosine of \a a (coeff-wise) */ -template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS -Packet pacos(const Packet& a) { using std::acos; return acos(a); } - -/** \internal \returns the exp of \a a (coeff-wise) */ -template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS -Packet pexp(const Packet& a) { using std::exp; return exp(a); } - -/** \internal \returns the log of \a a (coeff-wise) */ -template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS -Packet plog(const Packet& a) { using std::log; return log(a); } - -/** \internal \returns the square-root of \a a (coeff-wise) */ -template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS -Packet psqrt(const Packet& a) { using std::sqrt; return sqrt(a); } - -/*************************************************************************** -* The following functions might not have to be overwritten for vectorized types -***************************************************************************/ - -/** \internal copy a packet with constant coeficient \a a (e.g., [a,a,a,a]) to \a *to. \a to must be 16 bytes aligned */ -// NOTE: this function must really be templated on the packet type (think about different packet types for the same scalar type) -template -inline void pstore1(typename unpacket_traits::type* to, const typename unpacket_traits::type& a) -{ - pstore(to, pset1(a)); -} - -/** \internal \returns a * b + c (coeff-wise) */ -template inline Packet -pmadd(const Packet& a, - const Packet& b, - const Packet& c) -{ return padd(pmul(a, b),c); } - -/** \internal \returns a packet version of \a *from. - * If LoadMode equals #Aligned, \a from must be 16 bytes aligned */ -template -inline Packet ploadt(const typename unpacket_traits::type* from) -{ - if(LoadMode == Aligned) - return pload(from); - else - return ploadu(from); -} - -/** \internal copy the packet \a from to \a *to. - * If StoreMode equals #Aligned, \a to must be 16 bytes aligned */ -template -inline void pstoret(Scalar* to, const Packet& from) -{ - if(LoadMode == Aligned) - pstore(to, from); - else - pstoreu(to, from); -} - -/** \internal default implementation of palign() allowing partial specialization */ -template -struct palign_impl -{ - // by default data are aligned, so there is nothing to be done :) - static inline void run(PacketType&, const PacketType&) {} -}; - -/** \internal update \a first using the concatenation of the packet_size minus \a Offset last elements - * of \a first and \a Offset first elements of \a second. - * - * This function is currently only used to optimize matrix-vector products on unligned matrices. - * It takes 2 packets that represent a contiguous memory array, and returns a packet starting - * at the position \a Offset. For instance, for packets of 4 elements, we have: - * Input: - * - first = {f0,f1,f2,f3} - * - second = {s0,s1,s2,s3} - * Output: - * - if Offset==0 then {f0,f1,f2,f3} - * - if Offset==1 then {f1,f2,f3,s0} - * - if Offset==2 then {f2,f3,s0,s1} - * - if Offset==3 then {f3,s0,s1,s3} - */ -template -inline void palign(PacketType& first, const PacketType& second) -{ - palign_impl::run(first,second); -} - -/*************************************************************************** -* Fast complex products (GCC generates a function call which is very slow) -***************************************************************************/ - -template<> inline std::complex pmul(const std::complex& a, const std::complex& b) -{ return std::complex(real(a)*real(b) - imag(a)*imag(b), imag(a)*real(b) + real(a)*imag(b)); } - -template<> inline std::complex pmul(const std::complex& a, const std::complex& b) -{ return std::complex(real(a)*real(b) - imag(a)*imag(b), imag(a)*real(b) + real(a)*imag(b)); } - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_GENERIC_PACKET_MATH_H - diff --git a/splinter/src/Core/GlobalFunctions.h b/splinter/src/Core/GlobalFunctions.h deleted file mode 100644 index 2acf977233..0000000000 --- a/splinter/src/Core/GlobalFunctions.h +++ /dev/null @@ -1,92 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2010-2012 Gael Guennebaud -// Copyright (C) 2010 Benoit Jacob -// -// 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 - -#define EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(NAME,FUNCTOR) \ - template \ - inline const Eigen::CwiseUnaryOp, const Derived> \ - NAME(const Eigen::ArrayBase& x) { \ - return x.derived(); \ - } - -#define EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(NAME,FUNCTOR) \ - \ - template \ - struct NAME##_retval > \ - { \ - typedef const Eigen::CwiseUnaryOp, const Derived> type; \ - }; \ - template \ - struct NAME##_impl > \ - { \ - static inline typename NAME##_retval >::type run(const Eigen::ArrayBase& x) \ - { \ - return x.derived(); \ - } \ - }; - - -namespace Eigen -{ - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(real,scalar_real_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(imag,scalar_imag_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(conj,scalar_conjugate_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sin,scalar_sin_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cos,scalar_cos_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(asin,scalar_asin_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(acos,scalar_acos_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tan,scalar_tan_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(exp,scalar_exp_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log,scalar_log_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs,scalar_abs_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sqrt,scalar_sqrt_op) - - template - inline const Eigen::CwiseUnaryOp, const Derived> - 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() - ); - } - - /** - * \brief Component-wise division of a scalar by array elements. - **/ - template - inline const Eigen::CwiseUnaryOp, const Derived> - operator/(const 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) - EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(imag,scalar_imag_op) - EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(abs2,scalar_abs2_op) - } -} - -// TODO: cleanly disable those functions that are not supported on Array (numext::real_ref, internal::random, internal::isApprox...) - -#endif // EIGEN_GLOBAL_FUNCTIONS_H diff --git a/splinter/src/Core/MathFunctions.h b/splinter/src/Core/MathFunctions.h deleted file mode 100644 index 4e17ecd4b4..0000000000 --- a/splinter/src/Core/MathFunctions.h +++ /dev/null @@ -1,768 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2010 Benoit Jacob -// -// 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 - * - * What it does: - * Defines a typedef 'type' as follows: - * - if type T has a member typedef Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl, then - * global_math_functions_filtering_base::type is a typedef for it. - * - otherwise, global_math_functions_filtering_base::type is a typedef for T. - * - * How it's used: - * To allow to defined the global math functions (like sin...) in certain cases, like the Array expressions. - * When you do sin(array1+array2), the object array1+array2 has a complicated expression type, all what you want to know - * is that it inherits ArrayBase. So we implement a partial specialization of sin_impl for ArrayBase. - * So we must make sure to use sin_impl > and not sin_impl, otherwise our partial specialization - * won't be used. How does sin know that? That's exactly what global_math_functions_filtering_base tells it. - * - * How it's implemented: - * SFINAE in the style of enable_if. Highly susceptible of breaking compilers. With GCC, it sure does work, but if you replace - * the typename dummy by an integer template parameter, it doesn't work anymore! - */ - -template -struct global_math_functions_filtering_base -{ - typedef T type; -}; - -template struct always_void { typedef void type; }; - -template -struct global_math_functions_filtering_base - ::type - > -{ - typedef typename T::Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl type; -}; - -#define EIGEN_MATHFUNC_IMPL(func, scalar) Eigen::internal::func##_impl::type> -#define EIGEN_MATHFUNC_RETVAL(func, scalar) typename Eigen::internal::func##_retval::type>::type - -/**************************************************************************** -* Implementation of real * -****************************************************************************/ - -template::IsComplex> -struct real_default_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar run(const Scalar& x) - { - return x; - } -}; - -template -struct real_default_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar run(const Scalar& x) - { - using std::real; - return real(x); - } -}; - -template struct real_impl : real_default_impl {}; - -template -struct real_retval -{ - typedef typename NumTraits::Real type; -}; - - -/**************************************************************************** -* Implementation of imag * -****************************************************************************/ - -template::IsComplex> -struct imag_default_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar run(const Scalar&) - { - return RealScalar(0); - } -}; - -template -struct imag_default_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar run(const Scalar& x) - { - using std::imag; - return imag(x); - } -}; - -template struct imag_impl : imag_default_impl {}; - -template -struct imag_retval -{ - typedef typename NumTraits::Real type; -}; - -/**************************************************************************** -* Implementation of real_ref * -****************************************************************************/ - -template -struct real_ref_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar& run(Scalar& x) - { - return reinterpret_cast(&x)[0]; - } - static inline const RealScalar& run(const Scalar& x) - { - return reinterpret_cast(&x)[0]; - } -}; - -template -struct real_ref_retval -{ - typedef typename NumTraits::Real & type; -}; - -/**************************************************************************** -* Implementation of imag_ref * -****************************************************************************/ - -template -struct imag_ref_default_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar& run(Scalar& x) - { - return reinterpret_cast(&x)[1]; - } - static inline const RealScalar& run(const Scalar& x) - { - return reinterpret_cast(&x)[1]; - } -}; - -template -struct imag_ref_default_impl -{ - static inline Scalar run(Scalar&) - { - return Scalar(0); - } - static inline const Scalar run(const Scalar&) - { - return Scalar(0); - } -}; - -template -struct imag_ref_impl : imag_ref_default_impl::IsComplex> {}; - -template -struct imag_ref_retval -{ - typedef typename NumTraits::Real & type; -}; - -/**************************************************************************** -* Implementation of conj * -****************************************************************************/ - -template::IsComplex> -struct conj_impl -{ - static inline Scalar run(const Scalar& x) - { - return x; - } -}; - -template -struct conj_impl -{ - static inline Scalar run(const Scalar& x) - { - using std::conj; - return conj(x); - } -}; - -template -struct conj_retval -{ - typedef Scalar type; -}; - -/**************************************************************************** -* Implementation of abs2 * -****************************************************************************/ - -template -struct abs2_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar run(const Scalar& x) - { - return x*x; - } -}; - -template -struct abs2_impl > -{ - static inline RealScalar run(const std::complex& x) - { - return real(x)*real(x) + imag(x)*imag(x); - } -}; - -template -struct abs2_retval -{ - typedef typename NumTraits::Real type; -}; - -/**************************************************************************** -* Implementation of norm1 * -****************************************************************************/ - -template -struct norm1_default_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar run(const Scalar& x) - { - using std::abs; - return abs(real(x)) + abs(imag(x)); - } -}; - -template -struct norm1_default_impl -{ - static inline Scalar run(const Scalar& x) - { - using std::abs; - return abs(x); - } -}; - -template -struct norm1_impl : norm1_default_impl::IsComplex> {}; - -template -struct norm1_retval -{ - typedef typename NumTraits::Real type; -}; - -/**************************************************************************** -* Implementation of hypot * -****************************************************************************/ - -template -struct hypot_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar run(const Scalar& x, const Scalar& y) - { - using std::max; - using std::min; - using std::abs; - using std::sqrt; - RealScalar _x = abs(x); - RealScalar _y = abs(y); - RealScalar p = (max)(_x, _y); - if(p==RealScalar(0)) return RealScalar(0); - RealScalar q = (min)(_x, _y); - RealScalar qp = q/p; - return p * sqrt(RealScalar(1) + qp*qp); - } -}; - -template -struct hypot_retval -{ - typedef typename NumTraits::Real type; -}; - -/**************************************************************************** -* Implementation of cast * -****************************************************************************/ - -template -struct cast_impl -{ - static inline NewType run(const OldType& x) - { - return static_cast(x); - } -}; - -// here, for once, we're plainly returning NewType: we don't want cast to do weird things. - -template -inline NewType cast(const OldType& x) -{ - return cast_impl::run(x); -} - -/**************************************************************************** -* Implementation of atanh2 * -****************************************************************************/ - -template -struct atanh2_default_impl -{ - typedef Scalar retval; - typedef typename NumTraits::Real RealScalar; - static inline Scalar run(const Scalar& x, const Scalar& y) - { - using std::abs; - using std::log; - using std::sqrt; - Scalar z = x / y; - if (y == Scalar(0) || abs(z) > sqrt(NumTraits::epsilon())) - return RealScalar(0.5) * log((y + x) / (y - x)); - else - return z + z*z*z / RealScalar(3); - } -}; - -template -struct atanh2_default_impl -{ - static inline Scalar run(const Scalar&, const Scalar&) - { - EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) - return Scalar(0); - } -}; - -template -struct atanh2_impl : atanh2_default_impl::IsInteger> {}; - -template -struct atanh2_retval -{ - typedef Scalar type; -}; - -/**************************************************************************** -* Implementation of pow * -****************************************************************************/ - -template -struct pow_default_impl -{ - typedef Scalar retval; - static inline Scalar run(const Scalar& x, const Scalar& y) - { - using std::pow; - return pow(x, y); - } -}; - -template -struct pow_default_impl -{ - static inline Scalar run(Scalar x, Scalar y) - { - Scalar res(1); - eigen_assert(!NumTraits::IsSigned || y >= 0); - if(y & 1) res *= x; - y >>= 1; - while(y) - { - x *= x; - if(y&1) res *= x; - y >>= 1; - } - return res; - } -}; - -template -struct pow_impl : pow_default_impl::IsInteger> {}; - -template -struct pow_retval -{ - typedef Scalar type; -}; - -/**************************************************************************** -* Implementation of random * -****************************************************************************/ - -template -struct random_default_impl {}; - -template -struct random_impl : random_default_impl::IsComplex, NumTraits::IsInteger> {}; - -template -struct random_retval -{ - typedef Scalar type; -}; - -template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y); -template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(); - -template -struct random_default_impl -{ - static inline Scalar run(const Scalar& x, const Scalar& y) - { - return x + (y-x) * Scalar(std::rand()) / Scalar(RAND_MAX); - } - static inline Scalar run() - { - return run(Scalar(NumTraits::IsSigned ? -1 : 0), Scalar(1)); - } -}; - -enum { - floor_log2_terminate, - floor_log2_move_up, - floor_log2_move_down, - floor_log2_bogus -}; - -template struct floor_log2_selector -{ - enum { middle = (lower + upper) / 2, - value = (upper <= lower + 1) ? int(floor_log2_terminate) - : (n < (1 << middle)) ? int(floor_log2_move_down) - : (n==0) ? int(floor_log2_bogus) - : int(floor_log2_move_up) - }; -}; - -template::value> -struct floor_log2 {}; - -template -struct floor_log2 -{ - enum { value = floor_log2::middle>::value }; -}; - -template -struct floor_log2 -{ - enum { value = floor_log2::middle, upper>::value }; -}; - -template -struct floor_log2 -{ - enum { value = (n >= ((unsigned int)(1) << (lower+1))) ? lower+1 : lower }; -}; - -template -struct floor_log2 -{ - // no value, error at compile time -}; - -template -struct random_default_impl -{ - typedef typename NumTraits::NonInteger NonInteger; - - static inline Scalar run(const Scalar& x, const Scalar& y) - { - return x + Scalar((NonInteger(y)-x+1) * std::rand() / (RAND_MAX + NonInteger(1))); - } - - static inline Scalar run() - { -#ifdef EIGEN_MAKING_DOCS - return run(Scalar(NumTraits::IsSigned ? -10 : 0), Scalar(10)); -#else - enum { rand_bits = floor_log2<(unsigned int)(RAND_MAX)+1>::value, - scalar_bits = sizeof(Scalar) * CHAR_BIT, - shift = EIGEN_PLAIN_ENUM_MAX(0, int(rand_bits) - int(scalar_bits)), - offset = NumTraits::IsSigned ? (1 << (EIGEN_PLAIN_ENUM_MIN(rand_bits,scalar_bits)-1)) : 0 - }; - return Scalar((std::rand() >> shift) - offset); -#endif - } -}; - -template -struct random_default_impl -{ - static inline Scalar run(const Scalar& x, const Scalar& y) - { - return Scalar(random(real(x), real(y)), - random(imag(x), imag(y))); - } - static inline Scalar run() - { - typedef typename NumTraits::Real RealScalar; - return Scalar(random(), random()); - } -}; - -template -inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y) -{ - return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(x, y); -} - -template -inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random() -{ - return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(); -} - -} // end namespace internal - -/**************************************************************************** -* Generic math function * -****************************************************************************/ - -namespace numext { - -template -inline EIGEN_MATHFUNC_RETVAL(real, Scalar) real(const Scalar& x) -{ - return EIGEN_MATHFUNC_IMPL(real, Scalar)::run(x); -} - -template -inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) >::type real_ref(const Scalar& x) -{ - return internal::real_ref_impl::run(x); -} - -template -inline EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) real_ref(Scalar& x) -{ - return EIGEN_MATHFUNC_IMPL(real_ref, Scalar)::run(x); -} - -template -inline EIGEN_MATHFUNC_RETVAL(imag, Scalar) imag(const Scalar& x) -{ - return EIGEN_MATHFUNC_IMPL(imag, Scalar)::run(x); -} - -template -inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) >::type imag_ref(const Scalar& x) -{ - return internal::imag_ref_impl::run(x); -} - -template -inline EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) imag_ref(Scalar& x) -{ - return EIGEN_MATHFUNC_IMPL(imag_ref, Scalar)::run(x); -} - -template -inline EIGEN_MATHFUNC_RETVAL(conj, Scalar) conj(const Scalar& x) -{ - return EIGEN_MATHFUNC_IMPL(conj, Scalar)::run(x); -} - -template -inline EIGEN_MATHFUNC_RETVAL(abs2, Scalar) abs2(const Scalar& x) -{ - return EIGEN_MATHFUNC_IMPL(abs2, Scalar)::run(x); -} - -template -inline EIGEN_MATHFUNC_RETVAL(norm1, Scalar) norm1(const Scalar& x) -{ - return EIGEN_MATHFUNC_IMPL(norm1, Scalar)::run(x); -} - -template -inline EIGEN_MATHFUNC_RETVAL(hypot, Scalar) hypot(const Scalar& x, const Scalar& y) -{ - return EIGEN_MATHFUNC_IMPL(hypot, Scalar)::run(x, y); -} - -template -inline EIGEN_MATHFUNC_RETVAL(atanh2, Scalar) atanh2(const Scalar& x, const Scalar& y) -{ - return EIGEN_MATHFUNC_IMPL(atanh2, Scalar)::run(x, y); -} - -template -inline EIGEN_MATHFUNC_RETVAL(pow, Scalar) pow(const Scalar& x, const Scalar& y) -{ - return EIGEN_MATHFUNC_IMPL(pow, Scalar)::run(x, y); -} - -// 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 numext - -namespace internal { - -/**************************************************************************** -* Implementation of fuzzy comparisons * -****************************************************************************/ - -template -struct scalar_fuzzy_default_impl {}; - -template -struct scalar_fuzzy_default_impl -{ - typedef typename NumTraits::Real RealScalar; - template - static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) - { - using std::abs; - return abs(x) <= abs(y) * prec; - } - static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) - { - using std::min; - using std::abs; - return abs(x - y) <= (min)(abs(x), abs(y)) * prec; - } - static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar& prec) - { - return x <= y || isApprox(x, y, prec); - } -}; - -template -struct scalar_fuzzy_default_impl -{ - typedef typename NumTraits::Real RealScalar; - template - static inline bool isMuchSmallerThan(const Scalar& x, const Scalar&, const RealScalar&) - { - return x == Scalar(0); - } - static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar&) - { - return x == y; - } - static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar&) - { - return x <= y; - } -}; - -template -struct scalar_fuzzy_default_impl -{ - typedef typename NumTraits::Real RealScalar; - template - static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) - { - return numext::abs2(x) <= numext::abs2(y) * prec * prec; - } - static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) - { - using std::min; - return numext::abs2(x - y) <= (min)(numext::abs2(x), numext::abs2(y)) * prec * prec; - } -}; - -template -struct scalar_fuzzy_impl : scalar_fuzzy_default_impl::IsComplex, NumTraits::IsInteger> {}; - -template -inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, - const typename NumTraits::Real &precision = NumTraits::dummy_precision()) -{ - return scalar_fuzzy_impl::template isMuchSmallerThan(x, y, precision); -} - -template -inline bool isApprox(const Scalar& x, const Scalar& y, - const typename NumTraits::Real &precision = NumTraits::dummy_precision()) -{ - return scalar_fuzzy_impl::isApprox(x, y, precision); -} - -template -inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, - const typename NumTraits::Real &precision = NumTraits::dummy_precision()) -{ - return scalar_fuzzy_impl::isApproxOrLessThan(x, y, precision); -} - -/****************************************** -*** The special case of the bool type *** -******************************************/ - -template<> struct random_impl -{ - static inline bool run() - { - return random(0,1)==0 ? false : true; - } -}; - -template<> struct scalar_fuzzy_impl -{ - typedef bool RealScalar; - - template - static inline bool isMuchSmallerThan(const bool& x, const bool&, const bool&) - { - return !x; - } - - static inline bool isApprox(bool x, bool y, bool) - { - return x == y; - } - - static inline bool isApproxOrLessThan(const bool& x, const bool& y, const bool&) - { - return (!x) || y; - } - -}; - - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_MATHFUNCTIONS_H diff --git a/splinter/src/Core/ProductBase.h b/splinter/src/Core/ProductBase.h deleted file mode 100644 index cf74470a9a..0000000000 --- a/splinter/src/Core/ProductBase.h +++ /dev/null @@ -1,290 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009-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_PRODUCTBASE_H -#define EIGEN_PRODUCTBASE_H - -namespace Eigen { - -/** \class ProductBase - * \ingroup Core_Module - * - */ - -namespace internal { -template -struct traits > -{ - typedef MatrixXpr XprKind; - typedef typename remove_all<_Lhs>::type Lhs; - typedef typename remove_all<_Rhs>::type Rhs; - typedef typename scalar_product_traits::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 { - RowsAtCompileTime = traits::RowsAtCompileTime, - ColsAtCompileTime = traits::ColsAtCompileTime, - MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = traits::MaxColsAtCompileTime, - Flags = (MaxRowsAtCompileTime==1 ? RowMajorBit : 0) - | EvalBeforeNestingBit | EvalBeforeAssigningBit | NestByRefBit, - // Note that EvalBeforeNestingBit and NestByRefBit - // are not used in practice because nested is overloaded for products - CoeffReadCost = 0 // FIXME why is it needed ? - }; -}; -} - -#define EIGEN_PRODUCT_PUBLIC_INTERFACE(Derived) \ - typedef ProductBase Base; \ - EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \ - typedef typename Base::LhsNested LhsNested; \ - typedef typename Base::_LhsNested _LhsNested; \ - typedef typename Base::LhsBlasTraits LhsBlasTraits; \ - typedef typename Base::ActualLhsType ActualLhsType; \ - typedef typename Base::_ActualLhsType _ActualLhsType; \ - typedef typename Base::RhsNested RhsNested; \ - typedef typename Base::_RhsNested _RhsNested; \ - typedef typename Base::RhsBlasTraits RhsBlasTraits; \ - typedef typename Base::ActualRhsType ActualRhsType; \ - typedef typename Base::_ActualRhsType _ActualRhsType; \ - using Base::m_lhs; \ - using Base::m_rhs; - -template -class ProductBase : public MatrixBase -{ - public: - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(ProductBase) - - typedef typename Lhs::Nested LhsNested; - typedef typename internal::remove_all::type _LhsNested; - typedef internal::blas_traits<_LhsNested> LhsBlasTraits; - typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; - typedef typename internal::remove_all::type _ActualLhsType; - typedef typename internal::traits::Scalar LhsScalar; - - typedef typename Rhs::Nested RhsNested; - typedef typename internal::remove_all::type _RhsNested; - typedef internal::blas_traits<_RhsNested> RhsBlasTraits; - typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; - typedef typename internal::remove_all::type _ActualRhsType; - typedef typename internal::traits::Scalar RhsScalar; - - // Diagonal of a product: no need to evaluate the arguments because they are going to be evaluated only once - typedef CoeffBasedProduct FullyLazyCoeffBaseProductType; - - public: - -#ifndef EIGEN_NO_MALLOC - typedef typename Base::PlainObject BasePlainObject; - typedef Matrix DynPlainObject; - typedef typename internal::conditional<(BasePlainObject::SizeAtCompileTime==Dynamic) || (BasePlainObject::SizeAtCompileTime*int(sizeof(Scalar)) < int(EIGEN_STACK_ALLOCATION_LIMIT)), - BasePlainObject, DynPlainObject>::type PlainObject; -#else - typedef typename Base::PlainObject PlainObject; -#endif - - ProductBase(const Lhs& a_lhs, const Rhs& a_rhs) - : m_lhs(a_lhs), m_rhs(a_rhs) - { - eigen_assert(a_lhs.cols() == a_rhs.rows() - && "invalid matrix product" - && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); - } - - inline Index rows() const { return m_lhs.rows(); } - inline Index cols() const { return m_rhs.cols(); } - - template - inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst,Scalar(1)); } - - template - inline void addTo(Dest& dst) const { scaleAndAddTo(dst,Scalar(1)); } - - template - inline void subTo(Dest& dst) const { scaleAndAddTo(dst,Scalar(-1)); } - - template - inline void scaleAndAddTo(Dest& dst, const Scalar& alpha) const { derived().scaleAndAddTo(dst,alpha); } - - const _LhsNested& lhs() const { return m_lhs; } - const _RhsNested& rhs() const { return m_rhs; } - - // Implicit conversion to the nested type (trigger the evaluation of the product) - operator const PlainObject& () const - { - m_result.resize(m_lhs.rows(), m_rhs.cols()); - derived().evalTo(m_result); - return m_result; - } - - const Diagonal diagonal() const - { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs); } - - template - const Diagonal diagonal() const - { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs); } - - const Diagonal diagonal(Index index) const - { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs).diagonal(index); } - - // restrict coeff accessors to 1x1 expressions. No need to care about mutators here since this isnt a Lvalue expression - typename Base::CoeffReturnType coeff(Index row, Index col) const - { -#ifdef EIGEN2_SUPPORT - return lhs().row(row).cwiseProduct(rhs().col(col).transpose()).sum(); -#else - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - Matrix result = *this; - return result.coeff(row,col); -#endif - } - - typename Base::CoeffReturnType coeff(Index i) const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - Matrix result = *this; - return result.coeff(i); - } - - const Scalar& coeffRef(Index row, Index col) const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - return derived().coeffRef(row,col); - } - - const Scalar& coeffRef(Index i) const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - return derived().coeffRef(i); - } - - protected: - - LhsNested m_lhs; - RhsNested m_rhs; - - mutable PlainObject m_result; -}; - -// here we need to overload the nested rule for products -// such that the nested type is a const reference to a plain matrix -namespace internal { -template -struct nested, N, PlainObject> -{ - typedef typename GeneralProduct::PlainObject const& type; -}; -template -struct nested, N, PlainObject> -{ - typedef typename GeneralProduct::PlainObject const& type; -}; -} - -template -class ScaledProduct; - -// Note that these two operator* functions are not defined as member -// functions of ProductBase, because, otherwise we would have to -// define all overloads defined in MatrixBase. Furthermore, Using -// "using Base::operator*" would not work with MSVC. -// -// Also note that here we accept any compatible scalar types -template -const ScaledProduct -operator*(const ProductBase& prod, const typename Derived::Scalar& x) -{ return ScaledProduct(prod.derived(), x); } - -template -typename internal::enable_if::value, - const ScaledProduct >::type -operator*(const ProductBase& prod, const typename Derived::RealScalar& x) -{ return ScaledProduct(prod.derived(), x); } - - -template -const ScaledProduct -operator*(const typename Derived::Scalar& x,const ProductBase& prod) -{ return ScaledProduct(prod.derived(), x); } - -template -typename internal::enable_if::value, - const ScaledProduct >::type -operator*(const typename Derived::RealScalar& x,const ProductBase& prod) -{ return ScaledProduct(prod.derived(), x); } - -namespace internal { -template -struct traits > - : traits, - typename NestedProduct::_LhsNested, - typename NestedProduct::_RhsNested> > -{ - typedef typename traits::StorageKind StorageKind; -}; -} - -template -class ScaledProduct - : public ProductBase, - typename NestedProduct::_LhsNested, - typename NestedProduct::_RhsNested> -{ - public: - typedef ProductBase, - typename NestedProduct::_LhsNested, - typename NestedProduct::_RhsNested> Base; - typedef typename Base::Scalar Scalar; - typedef typename Base::PlainObject PlainObject; -// EIGEN_PRODUCT_PUBLIC_INTERFACE(ScaledProduct) - - ScaledProduct(const NestedProduct& prod, const Scalar& x) - : Base(prod.lhs(),prod.rhs()), m_prod(prod), m_alpha(x) {} - - template - inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst, Scalar(1)); } - - template - inline void addTo(Dest& dst) const { scaleAndAddTo(dst, Scalar(1)); } - - template - inline void subTo(Dest& dst) const { scaleAndAddTo(dst, Scalar(-1)); } - - template - inline void scaleAndAddTo(Dest& dst, const Scalar& a_alpha) const { m_prod.derived().scaleAndAddTo(dst,a_alpha * m_alpha); } - - const Scalar& alpha() const { return m_alpha; } - - protected: - const NestedProduct& m_prod; - Scalar m_alpha; -}; - -/** \internal - * Overloaded to perform an efficient C = (A*B).lazy() */ -template -template -Derived& MatrixBase::lazyAssign(const ProductBase& other) -{ - other.derived().evalTo(derived()); - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_PRODUCTBASE_H diff --git a/splinter/src/Core/Reverse.h b/splinter/src/Core/Reverse.h deleted file mode 100644 index e30ae3d281..0000000000 --- a/splinter/src/Core/Reverse.h +++ /dev/null @@ -1,224 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2008 Benoit Jacob -// Copyright (C) 2009 Ricard Marxer -// Copyright (C) 2009-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_REVERSE_H -#define EIGEN_REVERSE_H - -namespace Eigen { - -/** \class Reverse - * \ingroup Core_Module - * - * \brief Expression of the reverse of a vector or matrix - * - * \param MatrixType the type of the object of which we are taking the reverse - * - * This class represents an expression of the reverse of a vector. - * It is the return type of MatrixBase::reverse() and VectorwiseOp::reverse() - * and most of the time this is the only way it is used. - * - * \sa MatrixBase::reverse(), VectorwiseOp::reverse() - */ - -namespace internal { - -template -struct traits > - : traits -{ - typedef typename MatrixType::Scalar Scalar; - typedef typename traits::StorageKind StorageKind; - typedef typename traits::XprKind XprKind; - typedef typename nested::type MatrixTypeNested; - typedef typename remove_reference::type _MatrixTypeNested; - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime, - MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - - // let's enable LinearAccess only with vectorization because of the product overhead - LinearAccess = ( (Direction==BothDirections) && (int(_MatrixTypeNested::Flags)&PacketAccessBit) ) - ? LinearAccessBit : 0, - - Flags = int(_MatrixTypeNested::Flags) & (HereditaryBits | LvalueBit | PacketAccessBit | LinearAccess), - - CoeffReadCost = _MatrixTypeNested::CoeffReadCost - }; -}; - -template struct reverse_packet_cond -{ - static inline PacketScalar run(const PacketScalar& x) { return preverse(x); } -}; - -template struct reverse_packet_cond -{ - static inline PacketScalar run(const PacketScalar& x) { return x; } -}; - -} // end namespace internal - -template class Reverse - : public internal::dense_xpr_base< Reverse >::type -{ - public: - - typedef typename internal::dense_xpr_base::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(Reverse) - using Base::IsRowMajor; - - // next line is necessary because otherwise const version of operator() - // is hidden by non-const version defined in this file - using Base::operator(); - - protected: - enum { - PacketSize = internal::packet_traits::size, - IsColMajor = !IsRowMajor, - ReverseRow = (Direction == Vertical) || (Direction == BothDirections), - ReverseCol = (Direction == Horizontal) || (Direction == BothDirections), - OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, - OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1, - ReversePacket = (Direction == BothDirections) - || ((Direction == Vertical) && IsColMajor) - || ((Direction == Horizontal) && IsRowMajor) - }; - typedef internal::reverse_packet_cond reverse_packet; - public: - - inline Reverse(const MatrixType& matrix) : m_matrix(matrix) { } - - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Reverse) - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - - inline Index innerStride() const - { - return -m_matrix.innerStride(); - } - - inline Scalar& operator()(Index row, Index col) - { - eigen_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); - return coeffRef(row, col); - } - - inline Scalar& coeffRef(Index row, Index col) - { - return m_matrix.const_cast_derived().coeffRef(ReverseRow ? m_matrix.rows() - row - 1 : row, - ReverseCol ? m_matrix.cols() - col - 1 : col); - } - - inline CoeffReturnType coeff(Index row, Index col) const - { - return m_matrix.coeff(ReverseRow ? m_matrix.rows() - row - 1 : row, - ReverseCol ? m_matrix.cols() - col - 1 : col); - } - - inline CoeffReturnType coeff(Index index) const - { - return m_matrix.coeff(m_matrix.size() - index - 1); - } - - inline Scalar& coeffRef(Index index) - { - return m_matrix.const_cast_derived().coeffRef(m_matrix.size() - index - 1); - } - - inline Scalar& operator()(Index index) - { - eigen_assert(index >= 0 && index < m_matrix.size()); - return coeffRef(index); - } - - template - inline const PacketScalar packet(Index row, Index col) const - { - return reverse_packet::run(m_matrix.template packet( - ReverseRow ? m_matrix.rows() - row - OffsetRow : row, - ReverseCol ? m_matrix.cols() - col - OffsetCol : col)); - } - - template - inline void writePacket(Index row, Index col, const PacketScalar& x) - { - m_matrix.const_cast_derived().template writePacket( - ReverseRow ? m_matrix.rows() - row - OffsetRow : row, - ReverseCol ? m_matrix.cols() - col - OffsetCol : col, - reverse_packet::run(x)); - } - - template - inline const PacketScalar packet(Index index) const - { - return internal::preverse(m_matrix.template packet( m_matrix.size() - index - PacketSize )); - } - - template - inline void writePacket(Index index, const PacketScalar& x) - { - 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: - typename MatrixType::Nested m_matrix; -}; - -/** \returns an expression of the reverse of *this. - * - * Example: \include MatrixBase_reverse.cpp - * Output: \verbinclude MatrixBase_reverse.out - * - */ -template -inline typename DenseBase::ReverseReturnType -DenseBase::reverse() -{ - return derived(); -} - -/** This is the const version of reverse(). */ -template -inline const typename DenseBase::ConstReverseReturnType -DenseBase::reverse() const -{ - return derived(); -} - -/** This is the "in place" version of reverse: it reverses \c *this. - * - * In most cases it is probably better to simply use the reversed expression - * of a matrix. However, when reversing the matrix data itself is really needed, - * then this "in-place" version is probably the right choice because it provides - * the following additional features: - * - less error prone: doing the same operation with .reverse() requires special care: - * \code m = m.reverse().eval(); \endcode - * - this API allows to avoid creating a temporary (the current implementation creates a temporary, but that could be avoided using swap) - * - it allows future optimizations (cache friendliness, etc.) - * - * \sa reverse() */ -template -inline void DenseBase::reverseInPlace() -{ - derived() = derived().reverse().eval(); -} - -} // end namespace Eigen - -#endif // EIGEN_REVERSE_H diff --git a/splinter/src/Core/SelfAdjointView.h b/splinter/src/Core/SelfAdjointView.h deleted file mode 100644 index 6fa7cd15e6..0000000000 --- a/splinter/src/Core/SelfAdjointView.h +++ /dev/null @@ -1,314 +0,0 @@ -// 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_SELFADJOINTMATRIX_H -#define EIGEN_SELFADJOINTMATRIX_H - -namespace Eigen { - -/** \class SelfAdjointView - * \ingroup Core_Module - * - * - * \brief Expression of a selfadjoint matrix from a triangular part of a dense matrix - * - * \param MatrixType the type of the dense matrix storing the coefficients - * \param TriangularPart 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 class TriangularBase, MatrixBase::selfadjointView() - */ - -namespace internal { -template -struct traits > : traits -{ - typedef typename nested::type MatrixTypeNested; - typedef typename remove_all::type MatrixTypeNestedCleaned; - typedef MatrixType ExpressionType; - typedef typename MatrixType::PlainObject DenseMatrixType; - enum { - Mode = UpLo | SelfAdjoint, - Flags = MatrixTypeNestedCleaned::Flags & (HereditaryBits) - & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit)), // FIXME these flags should be preserved - CoeffReadCost = MatrixTypeNestedCleaned::CoeffReadCost - }; -}; -} - -template -struct SelfadjointProductMatrix; - -// FIXME could also be called SelfAdjointWrapper to be consistent with DiagonalWrapper ?? -template class SelfAdjointView - : public TriangularBase > -{ - public: - - typedef TriangularBase Base; - typedef typename internal::traits::MatrixTypeNested MatrixTypeNested; - typedef typename internal::traits::MatrixTypeNestedCleaned MatrixTypeNestedCleaned; - - /** \brief The type of coefficients in this matrix */ - typedef typename internal::traits::Scalar Scalar; - - typedef typename MatrixType::Index Index; - - enum { - Mode = internal::traits::Mode - }; - typedef typename MatrixType::PlainObject PlainObject; - - inline SelfAdjointView(MatrixType& matrix) : m_matrix(matrix) - {} - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - inline Index outerStride() const { return m_matrix.outerStride(); } - inline Index innerStride() const { return m_matrix.innerStride(); } - - /** \sa MatrixBase::coeff() - * \warning the coordinates must fit into the referenced triangular part - */ - inline Scalar coeff(Index row, Index col) const - { - Base::check_coordinates_internal(row, col); - return m_matrix.coeff(row, col); - } - - /** \sa MatrixBase::coeffRef() - * \warning the coordinates must fit into the referenced triangular part - */ - inline Scalar& coeffRef(Index row, Index col) - { - Base::check_coordinates_internal(row, col); - return m_matrix.const_cast_derived().coeffRef(row, col); - } - - /** \internal */ - const MatrixTypeNestedCleaned& _expression() const { return m_matrix; } - - const MatrixTypeNestedCleaned& nestedExpression() const { return m_matrix; } - MatrixTypeNestedCleaned& nestedExpression() { return *const_cast(&m_matrix); } - - /** Efficient self-adjoint matrix times vector/matrix product */ - template - SelfadjointProductMatrix - operator*(const MatrixBase& rhs) const - { - return SelfadjointProductMatrix - - (m_matrix, rhs.derived()); - } - - /** Efficient vector/matrix times self-adjoint matrix product */ - template friend - SelfadjointProductMatrix - operator*(const MatrixBase& lhs, const SelfAdjointView& rhs) - { - return SelfadjointProductMatrix - - (lhs.derived(),rhs.m_matrix); - } - - /** Perform a symmetric rank 2 update of the selfadjoint matrix \c *this: - * \f$ this = this + \alpha u v^* + conj(\alpha) v u^* \f$ - * \returns a reference to \c *this - * - * The vectors \a u and \c v \b must be column vectors, however they can be - * a adjoint expression without any overhead. Only the meaningful triangular - * part of the matrix is updated, the rest is left unchanged. - * - * \sa rankUpdate(const MatrixBase&, Scalar) - */ - template - SelfAdjointView& rankUpdate(const MatrixBase& u, const MatrixBase& v, const Scalar& alpha = Scalar(1)); - - /** 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 to perform \f$ this = this + \alpha ( u^* u ) \f$ you can simply - * call this function with u.adjoint(). - * - * \sa rankUpdate(const MatrixBase&, const MatrixBase&, Scalar) - */ - template - SelfAdjointView& rankUpdate(const MatrixBase& u, const Scalar& alpha = Scalar(1)); - -/////////// Cholesky module /////////// - - const LLT llt() const; - const LDLT ldlt() const; - -/////////// Eigenvalue module /////////// - - /** Real part of #Scalar */ - typedef typename NumTraits::Real RealScalar; - /** Return type of eigenvalues() */ - typedef Matrix::ColsAtCompileTime, 1> EigenvaluesReturnType; - - EigenvaluesReturnType eigenvalues() const; - RealScalar operatorNorm() const; - - #ifdef EIGEN2_SUPPORT - template - SelfAdjointView& operator=(const MatrixBase& other) - { - enum { - OtherPart = UpLo == Upper ? StrictlyLower : StrictlyUpper - }; - m_matrix.const_cast_derived().template triangularView() = other; - m_matrix.const_cast_derived().template triangularView() = other.adjoint(); - return *this; - } - template - SelfAdjointView& operator=(const TriangularView& other) - { - enum { - OtherPart = UpLo == Upper ? StrictlyLower : StrictlyUpper - }; - m_matrix.const_cast_derived().template triangularView() = other.toDenseMatrix(); - m_matrix.const_cast_derived().template triangularView() = other.toDenseMatrix().adjoint(); - return *this; - } - #endif - - protected: - MatrixTypeNested m_matrix; -}; - - -// template -// internal::selfadjoint_matrix_product_returntype > -// operator*(const MatrixBase& lhs, const SelfAdjointView& rhs) -// { -// return internal::matrix_selfadjoint_product_returntype >(lhs.derived(),rhs); -// } - -// selfadjoint to dense matrix - -namespace internal { - -template -struct triangular_assignment_selector -{ - enum { - col = (UnrollCount-1) / Derived1::RowsAtCompileTime, - row = (UnrollCount-1) % Derived1::RowsAtCompileTime - }; - - static inline void run(Derived1 &dst, const Derived2 &src) - { - triangular_assignment_selector::run(dst, src); - - if(row == col) - dst.coeffRef(row, col) = numext::real(src.coeff(row, col)); - else if(row < col) - dst.coeffRef(col, row) = numext::conj(dst.coeffRef(row, col) = src.coeff(row, col)); - } -}; - -template -struct triangular_assignment_selector -{ - static inline void run(Derived1 &, const Derived2 &) {} -}; - -template -struct triangular_assignment_selector -{ - enum { - col = (UnrollCount-1) / Derived1::RowsAtCompileTime, - row = (UnrollCount-1) % Derived1::RowsAtCompileTime - }; - - static inline void run(Derived1 &dst, const Derived2 &src) - { - triangular_assignment_selector::run(dst, src); - - if(row == col) - dst.coeffRef(row, col) = numext::real(src.coeff(row, col)); - else if(row > col) - dst.coeffRef(col, row) = numext::conj(dst.coeffRef(row, col) = src.coeff(row, col)); - } -}; - -template -struct triangular_assignment_selector -{ - static inline void run(Derived1 &, const Derived2 &) {} -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - for(Index i = 0; i < j; ++i) - { - dst.copyCoeff(i, j, src); - dst.coeffRef(j,i) = numext::conj(dst.coeff(i,j)); - } - dst.copyCoeff(j, j, src); - } - } -}; - -template -struct triangular_assignment_selector -{ - static inline void run(Derived1 &dst, const Derived2 &src) - { - typedef typename Derived1::Index Index; - for(Index i = 0; i < dst.rows(); ++i) - { - for(Index j = 0; j < i; ++j) - { - dst.copyCoeff(i, j, src); - dst.coeffRef(j,i) = numext::conj(dst.coeff(i,j)); - } - dst.copyCoeff(i, i, src); - } - } -}; - -} // end namespace internal - -/*************************************************************************** -* Implementation of MatrixBase methods -***************************************************************************/ - -template -template -typename MatrixBase::template ConstSelfAdjointViewReturnType::Type -MatrixBase::selfadjointView() const -{ - return derived(); -} - -template -template -typename MatrixBase::template SelfAdjointViewReturnType::Type -MatrixBase::selfadjointView() -{ - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_SELFADJOINTMATRIX_H diff --git a/splinter/src/Core/SelfCwiseBinaryOp.h b/splinter/src/Core/SelfCwiseBinaryOp.h deleted file mode 100644 index 0956475af5..0000000000 --- a/splinter/src/Core/SelfCwiseBinaryOp.h +++ /dev/null @@ -1,191 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009-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_SELFCWISEBINARYOP_H -#define EIGEN_SELFCWISEBINARYOP_H - -namespace Eigen { - -/** \class SelfCwiseBinaryOp - * \ingroup Core_Module - * - * \internal - * - * \brief Internal helper class for optimizing operators like +=, -= - * - * This is a pseudo expression class re-implementing the copyCoeff/copyPacket - * method to directly performs a +=/-= operations in an optimal way. In particular, - * this allows to make sure that the input/output data are loaded only once using - * aligned packet loads. - * - * \sa class SwapWrapper for a similar trick. - */ - -namespace internal { -template -struct traits > - : traits > -{ - enum { - // Note that it is still a good idea to preserve the DirectAccessBit - // so that assign can correctly align the data. - Flags = traits >::Flags | (Lhs::Flags&DirectAccessBit) | (Lhs::Flags&LvalueBit), - OuterStrideAtCompileTime = Lhs::OuterStrideAtCompileTime, - InnerStrideAtCompileTime = Lhs::InnerStrideAtCompileTime - }; -}; -} - -template class SelfCwiseBinaryOp - : public internal::dense_xpr_base< SelfCwiseBinaryOp >::type -{ - public: - - typedef typename internal::dense_xpr_base::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(SelfCwiseBinaryOp) - - typedef typename internal::packet_traits::type Packet; - - inline SelfCwiseBinaryOp(Lhs& xpr, const BinaryOp& func = BinaryOp()) : m_matrix(xpr), m_functor(func) {} - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - inline Index outerStride() const { return m_matrix.outerStride(); } - inline Index innerStride() const { return m_matrix.innerStride(); } - inline const Scalar* data() const { return m_matrix.data(); } - - // note that this function is needed by assign to correctly align loads/stores - // TODO make Assign use .data() - inline Scalar& coeffRef(Index row, Index col) - { - EIGEN_STATIC_ASSERT_LVALUE(Lhs) - return m_matrix.const_cast_derived().coeffRef(row, col); - } - inline const Scalar& coeffRef(Index row, Index col) const - { - return m_matrix.coeffRef(row, col); - } - - // note that this function is needed by assign to correctly align loads/stores - // TODO make Assign use .data() - inline Scalar& coeffRef(Index index) - { - EIGEN_STATIC_ASSERT_LVALUE(Lhs) - return m_matrix.const_cast_derived().coeffRef(index); - } - inline const Scalar& coeffRef(Index index) const - { - return m_matrix.const_cast_derived().coeffRef(index); - } - - template - void copyCoeff(Index row, Index col, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - Scalar& tmp = m_matrix.coeffRef(row,col); - tmp = m_functor(tmp, _other.coeff(row,col)); - } - - template - void copyCoeff(Index index, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(index >= 0 && index < m_matrix.size()); - Scalar& tmp = m_matrix.coeffRef(index); - tmp = m_functor(tmp, _other.coeff(index)); - } - - template - void copyPacket(Index row, Index col, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - m_matrix.template writePacket(row, col, - m_functor.packetOp(m_matrix.template packet(row, col),_other.template packet(row, col)) ); - } - - template - void copyPacket(Index index, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(index >= 0 && index < m_matrix.size()); - m_matrix.template writePacket(index, - m_functor.packetOp(m_matrix.template packet(index),_other.template packet(index)) ); - } - - // reimplement lazyAssign to handle complex *= real - // see CwiseBinaryOp ctor for details - template - EIGEN_STRONG_INLINE SelfCwiseBinaryOp& lazyAssign(const DenseBase& rhs) - { - EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Lhs,RhsDerived) - EIGEN_CHECK_BINARY_COMPATIBILIY(BinaryOp,typename Lhs::Scalar,typename RhsDerived::Scalar); - - #ifdef EIGEN_DEBUG_ASSIGN - internal::assign_traits::debug(); - #endif - eigen_assert(rows() == rhs.rows() && cols() == rhs.cols()); - internal::assign_impl::run(*this,rhs.derived()); - #ifndef EIGEN_NO_DEBUG - this->checkTransposeAliasing(rhs.derived()); - #endif - return *this; - } - - // overloaded to honor evaluation of special matrices - // maybe another solution would be to not use SelfCwiseBinaryOp - // at first... - SelfCwiseBinaryOp& operator=(const Rhs& _rhs) - { - typename internal::nested::type rhs(_rhs); - 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; - - private: - SelfCwiseBinaryOp& operator=(const SelfCwiseBinaryOp&); -}; - -template -inline Derived& DenseBase::operator*=(const Scalar& other) -{ - typedef typename Derived::PlainObject PlainObject; - SelfCwiseBinaryOp, Derived, typename PlainObject::ConstantReturnType> tmp(derived()); - tmp = PlainObject::Constant(rows(),cols(),other); - return derived(); -} - -template -inline Derived& DenseBase::operator/=(const Scalar& other) -{ - typedef typename Derived::PlainObject PlainObject; - SelfCwiseBinaryOp, Derived, typename PlainObject::ConstantReturnType> tmp(derived()); - tmp = PlainObject::Constant(rows(),cols(), other); - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_SELFCWISEBINARYOP_H diff --git a/splinter/src/Core/Swap.h b/splinter/src/Core/Swap.h deleted file mode 100644 index bf58bd5997..0000000000 --- a/splinter/src/Core/Swap.h +++ /dev/null @@ -1,126 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2008 Benoit Jacob -// -// 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 - * - * \internal - * - * \brief Internal helper class for swapping two expressions - */ -namespace internal { -template -struct traits > : traits {}; -} - -template class SwapWrapper - : public internal::dense_xpr_base >::type -{ - public: - - typedef typename internal::dense_xpr_base::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(SwapWrapper) - typedef typename internal::packet_traits::type Packet; - - inline SwapWrapper(ExpressionType& xpr) : m_expression(xpr) {} - - inline Index rows() const { return m_expression.rows(); } - 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 rowId, Index colId) - { - return m_expression.const_cast_derived().coeffRef(rowId, colId); - } - - inline Scalar& coeffRef(Index index) - { - return m_expression.const_cast_derived().coeffRef(index); - } - - inline Scalar& coeffRef(Index rowId, Index colId) const - { - return m_expression.coeffRef(rowId, colId); - } - - inline Scalar& coeffRef(Index index) const - { - return m_expression.coeffRef(index); - } - - template - void copyCoeff(Index rowId, Index colId, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(rowId >= 0 && rowId < rows() - && colId >= 0 && colId < cols()); - Scalar tmp = m_expression.coeff(rowId, colId); - m_expression.coeffRef(rowId, colId) = _other.coeff(rowId, colId); - _other.coeffRef(rowId, colId) = tmp; - } - - template - void copyCoeff(Index index, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(index >= 0 && index < m_expression.size()); - Scalar tmp = m_expression.coeff(index); - m_expression.coeffRef(index) = _other.coeff(index); - _other.coeffRef(index) = tmp; - } - - template - void copyPacket(Index rowId, Index colId, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(rowId >= 0 && rowId < rows() - && colId >= 0 && colId < cols()); - Packet tmp = m_expression.template packet(rowId, colId); - m_expression.template writePacket(rowId, colId, - _other.template packet(rowId, colId) - ); - _other.template writePacket(rowId, colId, tmp); - } - - template - void copyPacket(Index index, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(index >= 0 && index < m_expression.size()); - Packet tmp = m_expression.template packet(index); - m_expression.template writePacket(index, - _other.template packet(index) - ); - _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/splinter/src/Core/TriangularMatrix.h b/splinter/src/Core/TriangularMatrix.h deleted file mode 100644 index 4d65392c68..0000000000 --- a/splinter/src/Core/TriangularMatrix.h +++ /dev/null @@ -1,839 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Benoit Jacob -// 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_TRIANGULARMATRIX_H -#define EIGEN_TRIANGULARMATRIX_H - -namespace Eigen { - -namespace internal { - -template struct triangular_solve_retval; - -} - -/** \internal - * - * \class TriangularBase - * \ingroup Core_Module - * - * \brief Base class for triangular part in a matrix - */ -template class TriangularBase : public EigenBase -{ - public: - - enum { - Mode = internal::traits::Mode, - CoeffReadCost = internal::traits::CoeffReadCost, - RowsAtCompileTime = internal::traits::RowsAtCompileTime, - ColsAtCompileTime = internal::traits::ColsAtCompileTime, - MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime - }; - typedef typename internal::traits::Scalar Scalar; - typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; - typedef typename internal::traits::DenseMatrixType DenseMatrixType; - typedef DenseMatrixType DenseType; - - inline TriangularBase() { eigen_assert(!((Mode&UnitDiag) && (Mode&ZeroDiag))); } - - inline Index rows() const { return derived().rows(); } - inline Index cols() const { return derived().cols(); } - inline Index outerStride() const { return derived().outerStride(); } - inline Index innerStride() const { return derived().innerStride(); } - - inline Scalar coeff(Index row, Index col) const { return derived().coeff(row,col); } - inline Scalar& coeffRef(Index row, Index col) { return derived().coeffRef(row,col); } - - /** \see MatrixBase::copyCoeff(row,col) - */ - template - EIGEN_STRONG_INLINE void copyCoeff(Index row, Index col, Other& other) - { - derived().coeffRef(row, col) = other.coeff(row, col); - } - - inline Scalar operator()(Index row, Index col) const - { - check_coordinates(row, col); - return coeff(row,col); - } - inline Scalar& operator()(Index row, Index col) - { - check_coordinates(row, col); - return coeffRef(row,col); - } - - #ifndef EIGEN_PARSED_BY_DOXYGEN - inline const Derived& derived() const { return *static_cast(this); } - inline Derived& derived() { return *static_cast(this); } - #endif // not EIGEN_PARSED_BY_DOXYGEN - - template - void evalTo(MatrixBase &other) const; - template - void evalToLazy(MatrixBase &other) const; - - DenseMatrixType toDenseMatrix() const - { - DenseMatrixType res(rows(), cols()); - evalToLazy(res); - return res; - } - - protected: - - void check_coordinates(Index row, Index col) const - { - EIGEN_ONLY_USED_FOR_DEBUG(row); - EIGEN_ONLY_USED_FOR_DEBUG(col); - eigen_assert(col>=0 && col=0 && row=row) - || (mode==Lower && col<=row) - || ((mode==StrictlyUpper || mode==UnitUpper) && col>row) - || ((mode==StrictlyLower || mode==UnitLower) && col -struct traits > : traits -{ - typedef typename nested::type MatrixTypeNested; - typedef typename remove_reference::type MatrixTypeNestedNonRef; - typedef typename remove_all::type MatrixTypeNestedCleaned; - typedef MatrixType ExpressionType; - typedef typename MatrixType::PlainObject DenseMatrixType; - enum { - Mode = _Mode, - Flags = (MatrixTypeNestedCleaned::Flags & (HereditaryBits) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) | Mode, - CoeffReadCost = MatrixTypeNestedCleaned::CoeffReadCost - }; -}; -} - -template -struct TriangularProduct; - -template class TriangularView - : public TriangularBase > -{ - public: - - typedef TriangularBase Base; - typedef typename internal::traits::Scalar Scalar; - - typedef _MatrixType MatrixType; - typedef typename internal::traits::DenseMatrixType DenseMatrixType; - typedef DenseMatrixType PlainObject; - - protected: - typedef typename internal::traits::MatrixTypeNested MatrixTypeNested; - typedef typename internal::traits::MatrixTypeNestedNonRef MatrixTypeNestedNonRef; - typedef typename internal::traits::MatrixTypeNestedCleaned MatrixTypeNestedCleaned; - - typedef typename internal::remove_all::type MatrixConjugateReturnType; - - public: - using Base::evalToLazy; - - - typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; - - enum { - Mode = _Mode, - TransposeMode = (Mode & Upper ? Lower : 0) - | (Mode & Lower ? Upper : 0) - | (Mode & (UnitDiag)) - | (Mode & (ZeroDiag)) - }; - - inline TriangularView(const MatrixType& matrix) : m_matrix(matrix) - {} - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - inline Index outerStride() const { return m_matrix.outerStride(); } - inline Index innerStride() const { return m_matrix.innerStride(); } - - /** \sa MatrixBase::operator+=() */ - template TriangularView& operator+=(const DenseBase& other) { return *this = m_matrix + other.derived(); } - /** \sa MatrixBase::operator-=() */ - template TriangularView& operator-=(const DenseBase& other) { return *this = m_matrix - other.derived(); } - /** \sa MatrixBase::operator*=() */ - TriangularView& operator*=(const typename internal::traits::Scalar& other) { return *this = m_matrix * other; } - /** \sa MatrixBase::operator/=() */ - TriangularView& operator/=(const typename internal::traits::Scalar& other) { return *this = m_matrix / other; } - - /** \sa MatrixBase::fill() */ - void fill(const Scalar& value) { setConstant(value); } - /** \sa MatrixBase::setConstant() */ - TriangularView& setConstant(const Scalar& value) - { return *this = MatrixType::Constant(rows(), cols(), value); } - /** \sa MatrixBase::setZero() */ - TriangularView& setZero() { return setConstant(Scalar(0)); } - /** \sa MatrixBase::setOnes() */ - TriangularView& setOnes() { return setConstant(Scalar(1)); } - - /** \sa MatrixBase::coeff() - * \warning the coordinates must fit into the referenced triangular part - */ - inline Scalar coeff(Index row, Index col) const - { - Base::check_coordinates_internal(row, col); - return m_matrix.coeff(row, col); - } - - /** \sa MatrixBase::coeffRef() - * \warning the coordinates must fit into the referenced triangular part - */ - inline Scalar& coeffRef(Index row, Index col) - { - Base::check_coordinates_internal(row, col); - return m_matrix.const_cast_derived().coeffRef(row, col); - } - - const MatrixTypeNestedCleaned& nestedExpression() const { return m_matrix; } - MatrixTypeNestedCleaned& nestedExpression() { return *const_cast(&m_matrix); } - - /** Assigns a triangular matrix to a triangular part of a dense matrix */ - template - TriangularView& operator=(const TriangularBase& other); - - template - TriangularView& operator=(const MatrixBase& other); - - TriangularView& operator=(const TriangularView& other) - { return *this = other.nestedExpression(); } - - template - void lazyAssign(const TriangularBase& other); - - template - void lazyAssign(const MatrixBase& other); - - /** \sa MatrixBase::conjugate() */ - inline TriangularView conjugate() - { return m_matrix.conjugate(); } - /** \sa MatrixBase::conjugate() const */ - inline const TriangularView conjugate() const - { return m_matrix.conjugate(); } - - /** \sa MatrixBase::adjoint() const */ - inline const TriangularView adjoint() const - { return m_matrix.adjoint(); } - - /** \sa MatrixBase::transpose() */ - inline TriangularView,TransposeMode> transpose() - { - EIGEN_STATIC_ASSERT_LVALUE(MatrixType) - return m_matrix.const_cast_derived().transpose(); - } - /** \sa MatrixBase::transpose() const */ - inline const TriangularView,TransposeMode> transpose() const - { - return m_matrix.transpose(); - } - - /** Efficient triangular matrix times vector/matrix product */ - template - TriangularProduct - operator*(const MatrixBase& rhs) const - { - return TriangularProduct - - (m_matrix, rhs.derived()); - } - - /** Efficient vector/matrix times triangular matrix product */ - template friend - TriangularProduct - operator*(const MatrixBase& lhs, const TriangularView& rhs) - { - return TriangularProduct - - (lhs.derived(),rhs.m_matrix); - } - - #ifdef EIGEN2_SUPPORT - template - struct eigen2_product_return_type - { - typedef typename TriangularView::DenseMatrixType DenseMatrixType; - typedef typename OtherDerived::PlainObject::DenseType OtherPlainObject; - typedef typename ProductReturnType::Type ProdRetType; - typedef typename ProdRetType::PlainObject type; - }; - template - const typename eigen2_product_return_type::type - operator*(const EigenBase& rhs) const - { - typename OtherDerived::PlainObject::DenseType rhsPlainObject; - rhs.evalTo(rhsPlainObject); - return this->toDenseMatrix() * rhsPlainObject; - } - template - bool isApprox(const TriangularView& other, typename NumTraits::Real precision = NumTraits::dummy_precision()) const - { - return this->toDenseMatrix().isApprox(other.toDenseMatrix(), precision); - } - template - bool isApprox(const MatrixBase& other, typename NumTraits::Real precision = NumTraits::dummy_precision()) const - { - return this->toDenseMatrix().isApprox(other, precision); - } - #endif // EIGEN2_SUPPORT - - template - inline const internal::triangular_solve_retval - solve(const MatrixBase& other) const; - - template - void solveInPlace(const MatrixBase& other) const; - - template - inline const internal::triangular_solve_retval - solve(const MatrixBase& other) const - { return solve(other); } - - template - void solveInPlace(const MatrixBase& other) const - { return solveInPlace(other); } - - const SelfAdjointView selfadjointView() const - { - EIGEN_STATIC_ASSERT((Mode&UnitDiag)==0,PROGRAMMING_ERROR); - return SelfAdjointView(m_matrix); - } - SelfAdjointView selfadjointView() - { - EIGEN_STATIC_ASSERT((Mode&UnitDiag)==0,PROGRAMMING_ERROR); - return SelfAdjointView(m_matrix); - } - - template - void swap(TriangularBase const & other) - { - TriangularView,Mode>(const_cast(m_matrix)).lazyAssign(other.derived()); - } - - template - void swap(MatrixBase const & other) - { - SwapWrapper swaper(const_cast(m_matrix)); - TriangularView,Mode>(swaper).lazyAssign(other.derived()); - } - - Scalar determinant() const - { - if (Mode & UnitDiag) - return 1; - else if (Mode & ZeroDiag) - return 0; - else - return m_matrix.diagonal().prod(); - } - - // TODO simplify the following: - template - EIGEN_STRONG_INLINE TriangularView& operator=(const ProductBase& other) - { - setZero(); - return assignProduct(other.derived(),1); - } - - template - EIGEN_STRONG_INLINE TriangularView& operator+=(const ProductBase& other) - { - return assignProduct(other.derived(),1); - } - - template - EIGEN_STRONG_INLINE TriangularView& operator-=(const ProductBase& other) - { - return assignProduct(other.derived(),-1); - } - - - template - EIGEN_STRONG_INLINE TriangularView& operator=(const ScaledProduct& other) - { - setZero(); - return assignProduct(other.derived(),other.alpha()); - } - - template - EIGEN_STRONG_INLINE TriangularView& operator+=(const ScaledProduct& other) - { - return assignProduct(other.derived(),other.alpha()); - } - - template - EIGEN_STRONG_INLINE TriangularView& operator-=(const ScaledProduct& other) - { - return assignProduct(other.derived(),-other.alpha()); - } - - protected: - - template - EIGEN_STRONG_INLINE TriangularView& assignProduct(const ProductBase& prod, const Scalar& alpha); - - template - EIGEN_STRONG_INLINE TriangularView& assignProduct(const TriangularProduct& prod, const Scalar& alpha) - { - lazyAssign(alpha*prod.eval()); - return *this; - } - - MatrixTypeNested m_matrix; -}; - -/*************************************************************************** -* Implementation of triangular evaluation/assignment -***************************************************************************/ - -namespace internal { - -template -struct triangular_assignment_selector -{ - enum { - col = (UnrollCount-1) / Derived1::RowsAtCompileTime, - row = (UnrollCount-1) % Derived1::RowsAtCompileTime - }; - - typedef typename Derived1::Scalar Scalar; - - static inline void run(Derived1 &dst, const Derived2 &src) - { - triangular_assignment_selector::run(dst, src); - - eigen_assert( Mode == Upper || Mode == Lower - || Mode == StrictlyUpper || Mode == StrictlyLower - || Mode == UnitUpper || Mode == UnitLower); - if((Mode == Upper && row <= col) - || (Mode == Lower && row >= col) - || (Mode == StrictlyUpper && row < col) - || (Mode == StrictlyLower && row > col) - || (Mode == UnitUpper && row < col) - || (Mode == UnitLower && row > col)) - dst.copyCoeff(row, col, src); - else if(ClearOpposite) - { - if (Mode&UnitDiag && row==col) - dst.coeffRef(row, col) = Scalar(1); - else - dst.coeffRef(row, col) = Scalar(0); - } - } -}; - -// prevent buggy user code from causing an infinite recursion -template -struct triangular_assignment_selector -{ - static inline void run(Derived1 &, const Derived2 &) {} -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - typedef typename Derived1::Scalar Scalar; - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - Index maxi = (std::min)(j, dst.rows()-1); - for(Index i = 0; i <= maxi; ++i) - dst.copyCoeff(i, j, src); - if (ClearOpposite) - for(Index i = maxi+1; i < dst.rows(); ++i) - dst.coeffRef(i, j) = Scalar(0); - } - } -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - for(Index i = j; i < dst.rows(); ++i) - dst.copyCoeff(i, j, src); - Index maxi = (std::min)(j, dst.rows()); - if (ClearOpposite) - for(Index i = 0; i < maxi; ++i) - dst.coeffRef(i, j) = static_cast(0); - } - } -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - typedef typename Derived1::Scalar Scalar; - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - Index maxi = (std::min)(j, dst.rows()); - for(Index i = 0; i < maxi; ++i) - dst.copyCoeff(i, j, src); - if (ClearOpposite) - for(Index i = maxi; i < dst.rows(); ++i) - dst.coeffRef(i, j) = Scalar(0); - } - } -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - for(Index i = j+1; i < dst.rows(); ++i) - dst.copyCoeff(i, j, src); - Index maxi = (std::min)(j, dst.rows()-1); - if (ClearOpposite) - for(Index i = 0; i <= maxi; ++i) - dst.coeffRef(i, j) = static_cast(0); - } - } -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - Index maxi = (std::min)(j, dst.rows()); - for(Index i = 0; i < maxi; ++i) - dst.copyCoeff(i, j, src); - if (ClearOpposite) - { - for(Index i = maxi+1; i < dst.rows(); ++i) - dst.coeffRef(i, j) = 0; - } - } - dst.diagonal().setOnes(); - } -}; -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - Index maxi = (std::min)(j, dst.rows()); - for(Index i = maxi+1; i < dst.rows(); ++i) - dst.copyCoeff(i, j, src); - if (ClearOpposite) - { - for(Index i = 0; i < maxi; ++i) - dst.coeffRef(i, j) = 0; - } - } - dst.diagonal().setOnes(); - } -}; - -} // end namespace internal - -// FIXME should we keep that possibility -template -template -inline TriangularView& -TriangularView::operator=(const MatrixBase& other) -{ - if(OtherDerived::Flags & EvalBeforeAssigningBit) - { - typename internal::plain_matrix_type::type other_evaluated(other.rows(), other.cols()); - other_evaluated.template triangularView().lazyAssign(other.derived()); - lazyAssign(other_evaluated); - } - else - lazyAssign(other.derived()); - return *this; -} - -// FIXME should we keep that possibility -template -template -void TriangularView::lazyAssign(const MatrixBase& other) -{ - enum { - unroll = MatrixType::SizeAtCompileTime != Dynamic - && internal::traits::CoeffReadCost != Dynamic - && MatrixType::SizeAtCompileTime*internal::traits::CoeffReadCost/2 <= EIGEN_UNROLLING_LIMIT - }; - eigen_assert(m_matrix.rows() == other.rows() && m_matrix.cols() == other.cols()); - - internal::triangular_assignment_selector - ::run(m_matrix.const_cast_derived(), other.derived()); -} - - - -template -template -inline TriangularView& -TriangularView::operator=(const TriangularBase& other) -{ - eigen_assert(Mode == int(OtherDerived::Mode)); - if(internal::traits::Flags & EvalBeforeAssigningBit) - { - typename OtherDerived::DenseMatrixType other_evaluated(other.rows(), other.cols()); - other_evaluated.template triangularView().lazyAssign(other.derived().nestedExpression()); - lazyAssign(other_evaluated); - } - else - lazyAssign(other.derived().nestedExpression()); - return *this; -} - -template -template -void TriangularView::lazyAssign(const TriangularBase& other) -{ - enum { - unroll = MatrixType::SizeAtCompileTime != Dynamic - && internal::traits::CoeffReadCost != Dynamic - && MatrixType::SizeAtCompileTime * internal::traits::CoeffReadCost / 2 - <= EIGEN_UNROLLING_LIMIT - }; - eigen_assert(m_matrix.rows() == other.rows() && m_matrix.cols() == other.cols()); - - internal::triangular_assignment_selector - ::run(m_matrix.const_cast_derived(), other.derived().nestedExpression()); -} - -/*************************************************************************** -* Implementation of TriangularBase methods -***************************************************************************/ - -/** Assigns a triangular or selfadjoint matrix to a dense matrix. - * If the matrix is triangular, the opposite part is set to zero. */ -template -template -void TriangularBase::evalTo(MatrixBase &other) const -{ - if(internal::traits::Flags & EvalBeforeAssigningBit) - { - typename internal::plain_matrix_type::type other_evaluated(rows(), cols()); - evalToLazy(other_evaluated); - other.derived().swap(other_evaluated); - } - else - evalToLazy(other.derived()); -} - -/** Assigns a triangular or selfadjoint matrix to a dense matrix. - * If the matrix is triangular, the opposite part is set to zero. */ -template -template -void TriangularBase::evalToLazy(MatrixBase &other) const -{ - enum { - unroll = DenseDerived::SizeAtCompileTime != Dynamic - && internal::traits::CoeffReadCost != Dynamic - && DenseDerived::SizeAtCompileTime * internal::traits::CoeffReadCost / 2 - <= EIGEN_UNROLLING_LIMIT - }; - other.derived().resize(this->rows(), this->cols()); - - internal::triangular_assignment_selector - ::MatrixTypeNestedCleaned, Derived::Mode, - unroll ? int(DenseDerived::SizeAtCompileTime) : Dynamic, - true // clear the opposite triangular part - >::run(other.derived(), derived().nestedExpression()); -} - -/*************************************************************************** -* Implementation of TriangularView methods -***************************************************************************/ - -/*************************************************************************** -* Implementation of MatrixBase methods -***************************************************************************/ - -#ifdef EIGEN2_SUPPORT - -// implementation of part<>(), including the SelfAdjoint case. - -namespace internal { -template -struct eigen2_part_return_type -{ - typedef TriangularView type; -}; - -template -struct eigen2_part_return_type -{ - typedef SelfAdjointView type; -}; -} - -/** \deprecated use MatrixBase::triangularView() */ -template -template -const typename internal::eigen2_part_return_type::type MatrixBase::part() const -{ - return derived(); -} - -/** \deprecated use MatrixBase::triangularView() */ -template -template -typename internal::eigen2_part_return_type::type MatrixBase::part() -{ - return derived(); -} -#endif - -/** - * \returns an expression of a triangular view extracted from the current matrix - * - * The parameter \a Mode can have the following values: \c #Upper, \c #StrictlyUpper, \c #UnitUpper, - * \c #Lower, \c #StrictlyLower, \c #UnitLower. - * - * Example: \include MatrixBase_extract.cpp - * Output: \verbinclude MatrixBase_extract.out - * - * \sa class TriangularView - */ -template -template -typename MatrixBase::template TriangularViewReturnType::Type -MatrixBase::triangularView() -{ - return derived(); -} - -/** This is the const version of MatrixBase::triangularView() */ -template -template -typename MatrixBase::template ConstTriangularViewReturnType::Type -MatrixBase::triangularView() const -{ - return derived(); -} - -/** \returns true if *this is approximately equal to an upper triangular matrix, - * within the precision given by \a prec. - * - * \sa isLowerTriangular() - */ -template -bool MatrixBase::isUpperTriangular(const RealScalar& prec) const -{ - using std::abs; - RealScalar maxAbsOnUpperPart = static_cast(-1); - for(Index j = 0; j < cols(); ++j) - { - Index maxi = (std::min)(j, rows()-1); - for(Index i = 0; i <= maxi; ++i) - { - RealScalar absValue = abs(coeff(i,j)); - if(absValue > maxAbsOnUpperPart) maxAbsOnUpperPart = absValue; - } - } - RealScalar threshold = maxAbsOnUpperPart * prec; - for(Index j = 0; j < cols(); ++j) - for(Index i = j+1; i < rows(); ++i) - if(abs(coeff(i, j)) > threshold) return false; - return true; -} - -/** \returns true if *this is approximately equal to a lower triangular matrix, - * within the precision given by \a prec. - * - * \sa isUpperTriangular() - */ -template -bool MatrixBase::isLowerTriangular(const RealScalar& prec) const -{ - using std::abs; - RealScalar maxAbsOnLowerPart = static_cast(-1); - for(Index j = 0; j < cols(); ++j) - for(Index i = j; i < rows(); ++i) - { - RealScalar absValue = abs(coeff(i,j)); - if(absValue > maxAbsOnLowerPart) maxAbsOnLowerPart = absValue; - } - RealScalar threshold = maxAbsOnLowerPart * prec; - for(Index j = 1; j < cols(); ++j) - { - Index maxi = (std::min)(j, rows()-1); - for(Index i = 0; i < maxi; ++i) - if(abs(coeff(i, j)) > threshold) return false; - } - return true; -} - -} // end namespace Eigen - -#endif // EIGEN_TRIANGULARMATRIX_H diff --git a/splinter/src/Core/arch/AltiVec/Complex.h b/splinter/src/Core/arch/AltiVec/Complex.h deleted file mode 100644 index 68d9a2bff8..0000000000 --- a/splinter/src/Core/arch/AltiVec/Complex.h +++ /dev/null @@ -1,217 +0,0 @@ -// 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_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 }; -static Packet16uc p16uc_COMPLEX_RE = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 2), 8);//{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 }; -static Packet16uc p16uc_COMPLEX_IM = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 1), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 3), 8);//{ 4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15 }; -static Packet16uc p16uc_COMPLEX_REV = vec_sld(p16uc_REVERSE, p16uc_REVERSE, 8);//{ 4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11 }; -static Packet16uc p16uc_COMPLEX_REV2 = vec_sld(p16uc_FORWARD, p16uc_FORWARD, 8);//{ 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; -static Packet16uc p16uc_PSET_HI = (Packet16uc) vec_mergeh((Packet4ui) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet4ui) vec_splat((Packet4ui)p16uc_FORWARD, 1));//{ 0,1,2,3, 4,5,6,7, 0,1,2,3, 4,5,6,7 }; -static Packet16uc p16uc_PSET_LO = (Packet16uc) vec_mergeh((Packet4ui) vec_splat((Packet4ui)p16uc_FORWARD, 2), (Packet4ui) vec_splat((Packet4ui)p16uc_FORWARD, 3));//{ 8,9,10,11, 12,13,14,15, 8,9,10,11, 12,13,14,15 }; - -//---------- float ---------- -struct Packet2cf -{ - EIGEN_STRONG_INLINE Packet2cf() {} - EIGEN_STRONG_INLINE explicit Packet2cf(const Packet4f& a) : v(a) {} - Packet4f v; -}; - -template<> struct packet_traits > : default_packet_traits -{ - typedef Packet2cf type; - enum { - Vectorizable = 1, - AlignedOnScalar = 1, - size = 2, - - HasAdd = 1, - HasSub = 1, - HasMul = 1, - HasDiv = 1, - HasNegate = 1, - HasAbs = 0, - HasAbs2 = 0, - HasMin = 0, - HasMax = 0, - HasSetLinear = 0 - }; -}; - -template<> struct unpacket_traits { typedef std::complex type; enum {size=2}; }; - -template<> EIGEN_STRONG_INLINE Packet2cf pset1(const std::complex& from) -{ - Packet2cf res; - /* On AltiVec we cannot load 64-bit registers, so wa have to take care of alignment */ - if((ptrdiff_t(&from) % 16) == 0) - res.v = pload((const float *)&from); - else - res.v = ploadu((const float *)&from); - res.v = vec_perm(res.v, res.v, p16uc_PSET_HI); - return res; -} - -template<> EIGEN_STRONG_INLINE Packet2cf padd(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_add(a.v,b.v)); } -template<> EIGEN_STRONG_INLINE Packet2cf psub(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_sub(a.v,b.v)); } -template<> EIGEN_STRONG_INLINE Packet2cf pnegate(const Packet2cf& a) { return Packet2cf(pnegate(a.v)); } -template<> EIGEN_STRONG_INLINE Packet2cf pconj(const Packet2cf& a) { return Packet2cf((Packet4f)vec_xor((Packet4ui)a.v, p4ui_CONJ_XOR)); } - -template<> EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, const Packet2cf& b) -{ - Packet4f v1, v2; - - // Permute and multiply the real parts of a and b - v1 = vec_perm(a.v, a.v, p16uc_COMPLEX_RE); - // Get the imaginary parts of a - v2 = vec_perm(a.v, a.v, p16uc_COMPLEX_IM); - // multiply a_re * b - v1 = vec_madd(v1, b.v, p4f_ZERO); - // multiply a_im * b and get the conjugate result - v2 = vec_madd(v2, b.v, p4f_ZERO); - v2 = (Packet4f) vec_xor((Packet4ui)v2, p4ui_CONJ_XOR); - // permute back to a proper order - v2 = vec_perm(v2, v2, p16uc_COMPLEX_REV); - - return Packet2cf(vec_add(v1, v2)); -} - -template<> EIGEN_STRONG_INLINE Packet2cf pand (const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_and(a.v,b.v)); } -template<> EIGEN_STRONG_INLINE Packet2cf por (const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_or(a.v,b.v)); } -template<> EIGEN_STRONG_INLINE Packet2cf pxor (const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_xor(a.v,b.v)); } -template<> EIGEN_STRONG_INLINE Packet2cf pandnot(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(vec_and(a.v, vec_nor(b.v,b.v))); } - -template<> EIGEN_STRONG_INLINE Packet2cf pload (const std::complex* from) { EIGEN_DEBUG_ALIGNED_LOAD return Packet2cf(pload((const float*)from)); } -template<> EIGEN_STRONG_INLINE Packet2cf ploadu(const std::complex* from) { EIGEN_DEBUG_UNALIGNED_LOAD return Packet2cf(ploadu((const float*)from)); } - -template<> EIGEN_STRONG_INLINE Packet2cf ploaddup(const std::complex* from) -{ - return pset1(*from); -} - -template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet2cf& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((float*)to, from.v); } -template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet2cf& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((float*)to, from.v); } - -template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { vec_dstt((float *)addr, DST_CTRL(2,2,32), DST_CHAN); } - -template<> EIGEN_STRONG_INLINE std::complex pfirst(const Packet2cf& a) -{ - std::complex EIGEN_ALIGN16 res[2]; - pstore((float *)&res, a.v); - - return res[0]; -} - -template<> EIGEN_STRONG_INLINE Packet2cf preverse(const Packet2cf& a) -{ - Packet4f rev_a; - rev_a = vec_perm(a.v, a.v, p16uc_COMPLEX_REV2); - return Packet2cf(rev_a); -} - -template<> EIGEN_STRONG_INLINE std::complex predux(const Packet2cf& a) -{ - Packet4f b; - b = (Packet4f) vec_sld(a.v, a.v, 8); - b = padd(a.v, b); - return pfirst(Packet2cf(b)); -} - -template<> EIGEN_STRONG_INLINE Packet2cf preduxp(const Packet2cf* vecs) -{ - Packet4f b1, b2; - - b1 = (Packet4f) vec_sld(vecs[0].v, vecs[1].v, 8); - b2 = (Packet4f) vec_sld(vecs[1].v, vecs[0].v, 8); - b2 = (Packet4f) vec_sld(b2, b2, 8); - b2 = padd(b1, b2); - - return Packet2cf(b2); -} - -template<> EIGEN_STRONG_INLINE std::complex predux_mul(const Packet2cf& a) -{ - Packet4f b; - Packet2cf prod; - b = (Packet4f) vec_sld(a.v, a.v, 8); - prod = pmul(a, Packet2cf(b)); - - return pfirst(prod); -} - -template -struct palign_impl -{ - static EIGEN_STRONG_INLINE void run(Packet2cf& first, const Packet2cf& second) - { - if (Offset==1) - { - first.v = vec_sld(first.v, second.v, 8); - } - } -}; - -template<> struct conj_helper -{ - EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet2cf& x, const Packet2cf& y, const Packet2cf& c) const - { return padd(pmul(x,y),c); } - - EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, const Packet2cf& b) const - { - return internal::pmul(a, pconj(b)); - } -}; - -template<> struct conj_helper -{ - EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet2cf& x, const Packet2cf& y, const Packet2cf& c) const - { return padd(pmul(x,y),c); } - - EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, const Packet2cf& b) const - { - return internal::pmul(pconj(a), b); - } -}; - -template<> struct conj_helper -{ - EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet2cf& x, const Packet2cf& y, const Packet2cf& c) const - { return padd(pmul(x,y),c); } - - EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, const Packet2cf& b) const - { - return pconj(internal::pmul(a, b)); - } -}; - -template<> EIGEN_STRONG_INLINE Packet2cf pdiv(const Packet2cf& a, const Packet2cf& b) -{ - // TODO optimize it for AltiVec - Packet2cf res = conj_helper().pmul(a,b); - Packet4f s = vec_madd(b.v, b.v, p4f_ZERO); - return Packet2cf(pdiv(res.v, vec_add(s,vec_perm(s, s, p16uc_COMPLEX_REV)))); -} - -template<> EIGEN_STRONG_INLINE Packet2cf pcplxflip(const Packet2cf& x) -{ - return Packet2cf(vec_perm(x.v, x.v, p16uc_COMPLEX_REV)); -} - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_COMPLEX_ALTIVEC_H diff --git a/splinter/src/Core/arch/AltiVec/PacketMath.h b/splinter/src/Core/arch/AltiVec/PacketMath.h deleted file mode 100644 index e4089962de..0000000000 --- a/splinter/src/Core/arch/AltiVec/PacketMath.h +++ /dev/null @@ -1,501 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Konstantinos Margaritis -// -// 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 -#define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 4 -#endif - -#ifndef EIGEN_HAS_FUSE_CJMADD -#define EIGEN_HAS_FUSE_CJMADD 1 -#endif - -// NOTE Altivec has 32 registers, but Eigen only accepts a value of 8 or 16 -#ifndef EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS -#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 16 -#endif - -typedef __vector float Packet4f; -typedef __vector int Packet4i; -typedef __vector unsigned int Packet4ui; -typedef __vector __bool int Packet4bi; -typedef __vector short int Packet8i; -typedef __vector unsigned char Packet16uc; - -// We don't want to write the same code all the time, but we need to reuse the constants -// and it doesn't really work to declare them global, so we define macros instead - -#define _EIGEN_DECLARE_CONST_FAST_Packet4f(NAME,X) \ - Packet4f p4f_##NAME = (Packet4f) vec_splat_s32(X) - -#define _EIGEN_DECLARE_CONST_FAST_Packet4i(NAME,X) \ - Packet4i p4i_##NAME = vec_splat_s32(X) - -#define _EIGEN_DECLARE_CONST_Packet4f(NAME,X) \ - Packet4f p4f_##NAME = pset1(X) - -#define _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(NAME,X) \ - Packet4f p4f_##NAME = vreinterpretq_f32_u32(pset1(X)) - -#define _EIGEN_DECLARE_CONST_Packet4i(NAME,X) \ - Packet4i p4i_##NAME = pset1(X) - -#define DST_CHAN 1 -#define DST_CTRL(size, count, stride) (((size) << 24) | ((count) << 16) | (stride)) - -// Define global static constants: -static Packet4f p4f_COUNTDOWN = { 3.0, 2.0, 1.0, 0.0 }; -static Packet4i p4i_COUNTDOWN = { 3, 2, 1, 0 }; -static Packet16uc p16uc_REVERSE = {12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3}; -static Packet16uc p16uc_FORWARD = vec_lvsl(0, (float*)0); -static Packet16uc p16uc_DUPLICATE = {0,1,2,3, 0,1,2,3, 4,5,6,7, 4,5,6,7}; - -static _EIGEN_DECLARE_CONST_FAST_Packet4f(ZERO, 0); -static _EIGEN_DECLARE_CONST_FAST_Packet4i(ZERO, 0); -static _EIGEN_DECLARE_CONST_FAST_Packet4i(ONE,1); -static _EIGEN_DECLARE_CONST_FAST_Packet4i(MINUS16,-16); -static _EIGEN_DECLARE_CONST_FAST_Packet4i(MINUS1,-1); -static Packet4f p4f_ONE = vec_ctf(p4i_ONE, 0); -static Packet4f p4f_ZERO_ = (Packet4f) vec_sl((Packet4ui)p4i_MINUS1, (Packet4ui)p4i_MINUS1); - -template<> struct packet_traits : default_packet_traits -{ - typedef Packet4f type; - enum { - Vectorizable = 1, - AlignedOnScalar = 1, - size=4, - - // FIXME check the Has* - HasSin = 0, - HasCos = 0, - HasLog = 0, - HasExp = 0, - HasSqrt = 0 - }; -}; -template<> struct packet_traits : default_packet_traits -{ - typedef Packet4i type; - enum { - // FIXME check the Has* - Vectorizable = 1, - AlignedOnScalar = 1, - size=4 - }; -}; - -template<> struct unpacket_traits { typedef float type; enum {size=4}; }; -template<> struct unpacket_traits { typedef int type; enum {size=4}; }; -/* -inline std::ostream & operator <<(std::ostream & s, const Packet4f & v) -{ - union { - Packet4f v; - float n[4]; - } vt; - vt.v = v; - s << vt.n[0] << ", " << vt.n[1] << ", " << vt.n[2] << ", " << vt.n[3]; - return s; -} - -inline std::ostream & operator <<(std::ostream & s, const Packet4i & v) -{ - union { - Packet4i v; - int n[4]; - } vt; - vt.v = v; - s << vt.n[0] << ", " << vt.n[1] << ", " << vt.n[2] << ", " << vt.n[3]; - return s; -} - -inline std::ostream & operator <<(std::ostream & s, const Packet4ui & v) -{ - union { - Packet4ui v; - unsigned int n[4]; - } vt; - vt.v = v; - s << vt.n[0] << ", " << vt.n[1] << ", " << vt.n[2] << ", " << vt.n[3]; - return s; -} - -inline std::ostream & operator <<(std::ostream & s, const Packetbi & v) -{ - union { - Packet4bi v; - unsigned int n[4]; - } vt; - vt.v = v; - s << vt.n[0] << ", " << vt.n[1] << ", " << vt.n[2] << ", " << vt.n[3]; - return s; -} -*/ -template<> EIGEN_STRONG_INLINE Packet4f pset1(const float& from) { - // Taken from http://developer.apple.com/hardwaredrivers/ve/alignment.html - float EIGEN_ALIGN16 af[4]; - af[0] = from; - Packet4f vc = vec_ld(0, af); - vc = vec_splat(vc, 0); - return vc; -} - -template<> EIGEN_STRONG_INLINE Packet4i pset1(const int& from) { - int EIGEN_ALIGN16 ai[4]; - ai[0] = from; - Packet4i vc = vec_ld(0, ai); - vc = vec_splat(vc, 0); - return vc; -} - -template<> EIGEN_STRONG_INLINE Packet4f plset(const float& a) { return vec_add(pset1(a), p4f_COUNTDOWN); } -template<> EIGEN_STRONG_INLINE Packet4i plset(const int& a) { return vec_add(pset1(a), p4i_COUNTDOWN); } - -template<> EIGEN_STRONG_INLINE Packet4f padd(const Packet4f& a, const Packet4f& b) { return vec_add(a,b); } -template<> EIGEN_STRONG_INLINE Packet4i padd(const Packet4i& a, const Packet4i& b) { return vec_add(a,b); } - -template<> EIGEN_STRONG_INLINE Packet4f psub(const Packet4f& a, const Packet4f& b) { return vec_sub(a,b); } -template<> EIGEN_STRONG_INLINE Packet4i psub(const Packet4i& a, const Packet4i& b) { return vec_sub(a,b); } - -template<> EIGEN_STRONG_INLINE Packet4f pnegate(const Packet4f& a) { return psub(p4f_ZERO, a); } -template<> EIGEN_STRONG_INLINE Packet4i pnegate(const Packet4i& a) { return psub(p4i_ZERO, a); } - -template<> EIGEN_STRONG_INLINE Packet4f pconj(const Packet4f& a) { return a; } -template<> EIGEN_STRONG_INLINE Packet4i pconj(const Packet4i& a) { return a; } - -template<> EIGEN_STRONG_INLINE Packet4f pmul(const Packet4f& a, const Packet4f& b) { return vec_madd(a,b,p4f_ZERO); } -/* Commented out: it's actually slower than processing it scalar - * -template<> EIGEN_STRONG_INLINE Packet4i pmul(const Packet4i& a, const Packet4i& b) -{ - // Detailed in: http://freevec.org/content/32bit_signed_integer_multiplication_altivec - //Set up constants, variables - Packet4i a1, b1, bswap, low_prod, high_prod, prod, prod_, v1sel; - - // Get the absolute values - a1 = vec_abs(a); - b1 = vec_abs(b); - - // Get the signs using xor - Packet4bi sgn = (Packet4bi) vec_cmplt(vec_xor(a, b), p4i_ZERO); - - // Do the multiplication for the asbolute values. - bswap = (Packet4i) vec_rl((Packet4ui) b1, (Packet4ui) p4i_MINUS16 ); - low_prod = vec_mulo((Packet8i) a1, (Packet8i)b1); - high_prod = vec_msum((Packet8i) a1, (Packet8i) bswap, p4i_ZERO); - high_prod = (Packet4i) vec_sl((Packet4ui) high_prod, (Packet4ui) p4i_MINUS16); - prod = vec_add( low_prod, high_prod ); - - // NOR the product and select only the negative elements according to the sign mask - prod_ = vec_nor(prod, prod); - prod_ = vec_sel(p4i_ZERO, prod_, sgn); - - // Add 1 to the result to get the negative numbers - v1sel = vec_sel(p4i_ZERO, p4i_ONE, sgn); - prod_ = vec_add(prod_, v1sel); - - // Merge the results back to the final vector. - prod = vec_sel(prod, prod_, sgn); - - return prod; -} -*/ -template<> EIGEN_STRONG_INLINE Packet4f pdiv(const Packet4f& a, const Packet4f& b) -{ - Packet4f t, y_0, y_1, res; - - // Altivec does not offer a divide instruction, we have to do a reciprocal approximation - y_0 = vec_re(b); - - // Do one Newton-Raphson iteration to get the needed accuracy - t = vec_nmsub(y_0, b, p4f_ONE); - y_1 = vec_madd(y_0, t, y_0); - - res = vec_madd(a, y_1, p4f_ZERO); - return res; -} - -template<> EIGEN_STRONG_INLINE Packet4i pdiv(const Packet4i& /*a*/, const Packet4i& /*b*/) -{ eigen_assert(false && "packet integer division are not supported by AltiVec"); - return pset1(0); -} - -// for some weird raisons, it has to be overloaded for packet of integers -template<> EIGEN_STRONG_INLINE Packet4f pmadd(const Packet4f& a, const Packet4f& b, const Packet4f& c) { return vec_madd(a, b, c); } -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 pmin(const Packet4f& a, const Packet4f& b) { return vec_min(a, b); } -template<> EIGEN_STRONG_INLINE Packet4i pmin(const Packet4i& a, const Packet4i& b) { return vec_min(a, b); } - -template<> EIGEN_STRONG_INLINE Packet4f pmax(const Packet4f& a, const Packet4f& b) { return vec_max(a, b); } -template<> EIGEN_STRONG_INLINE Packet4i pmax(const Packet4i& a, const Packet4i& b) { return vec_max(a, b); } - -// Logical Operations are not supported for float, so we have to reinterpret casts using NEON intrinsics -template<> EIGEN_STRONG_INLINE Packet4f pand(const Packet4f& a, const Packet4f& b) { return vec_and(a, b); } -template<> EIGEN_STRONG_INLINE Packet4i pand(const Packet4i& a, const Packet4i& b) { return vec_and(a, b); } - -template<> EIGEN_STRONG_INLINE Packet4f por(const Packet4f& a, const Packet4f& b) { return vec_or(a, b); } -template<> EIGEN_STRONG_INLINE Packet4i por(const Packet4i& a, const Packet4i& b) { return vec_or(a, b); } - -template<> EIGEN_STRONG_INLINE Packet4f pxor(const Packet4f& a, const Packet4f& b) { return vec_xor(a, b); } -template<> EIGEN_STRONG_INLINE Packet4i pxor(const Packet4i& a, const Packet4i& b) { return vec_xor(a, b); } - -template<> EIGEN_STRONG_INLINE Packet4f pandnot(const Packet4f& a, const Packet4f& b) { return vec_and(a, vec_nor(b, b)); } -template<> EIGEN_STRONG_INLINE Packet4i pandnot(const Packet4i& a, const Packet4i& b) { return vec_and(a, vec_nor(b, b)); } - -template<> EIGEN_STRONG_INLINE Packet4f pload(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD return vec_ld(0, from); } -template<> EIGEN_STRONG_INLINE Packet4i pload(const int* from) { EIGEN_DEBUG_ALIGNED_LOAD return vec_ld(0, from); } - -template<> EIGEN_STRONG_INLINE Packet4f ploadu(const float* from) -{ - EIGEN_DEBUG_ALIGNED_LOAD - // Taken from http://developer.apple.com/hardwaredrivers/ve/alignment.html - Packet16uc MSQ, LSQ; - Packet16uc mask; - MSQ = vec_ld(0, (unsigned char *)from); // most significant quadword - LSQ = vec_ld(15, (unsigned char *)from); // least significant quadword - mask = vec_lvsl(0, from); // create the permute mask - return (Packet4f) vec_perm(MSQ, LSQ, mask); // align the data - -} -template<> EIGEN_STRONG_INLINE Packet4i ploadu(const int* from) -{ - EIGEN_DEBUG_ALIGNED_LOAD - // Taken from http://developer.apple.com/hardwaredrivers/ve/alignment.html - Packet16uc MSQ, LSQ; - Packet16uc mask; - MSQ = vec_ld(0, (unsigned char *)from); // most significant quadword - LSQ = vec_ld(15, (unsigned char *)from); // least significant quadword - mask = vec_lvsl(0, from); // create the permute mask - return (Packet4i) vec_perm(MSQ, LSQ, mask); // align the data -} - -template<> EIGEN_STRONG_INLINE Packet4f ploaddup(const float* from) -{ - Packet4f p; - if((ptrdiff_t(&from) % 16) == 0) p = pload(from); - else p = ploadu(from); - return vec_perm(p, p, p16uc_DUPLICATE); -} -template<> EIGEN_STRONG_INLINE Packet4i ploaddup(const int* from) -{ - Packet4i p; - if((ptrdiff_t(&from) % 16) == 0) p = pload(from); - else p = ploadu(from); - return vec_perm(p, p, p16uc_DUPLICATE); -} - -template<> EIGEN_STRONG_INLINE void pstore(float* to, const Packet4f& from) { EIGEN_DEBUG_ALIGNED_STORE vec_st(from, 0, to); } -template<> EIGEN_STRONG_INLINE void pstore(int* to, const Packet4i& from) { EIGEN_DEBUG_ALIGNED_STORE vec_st(from, 0, to); } - -template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet4f& from) -{ - EIGEN_DEBUG_UNALIGNED_STORE - // Taken from http://developer.apple.com/hardwaredrivers/ve/alignment.html - // Warning: not thread safe! - Packet16uc MSQ, LSQ, edges; - Packet16uc edgeAlign, align; - - MSQ = vec_ld(0, (unsigned char *)to); // most significant quadword - LSQ = vec_ld(15, (unsigned char *)to); // least significant quadword - edgeAlign = vec_lvsl(0, to); // permute map to extract edges - edges=vec_perm(LSQ,MSQ,edgeAlign); // extract the edges - align = vec_lvsr( 0, to ); // permute map to misalign data - MSQ = vec_perm(edges,(Packet16uc)from,align); // misalign the data (MSQ) - LSQ = vec_perm((Packet16uc)from,edges,align); // misalign the data (LSQ) - vec_st( LSQ, 15, (unsigned char *)to ); // Store the LSQ part first - vec_st( MSQ, 0, (unsigned char *)to ); // Store the MSQ part -} -template<> EIGEN_STRONG_INLINE void pstoreu(int* to, const Packet4i& from) -{ - EIGEN_DEBUG_UNALIGNED_STORE - // Taken from http://developer.apple.com/hardwaredrivers/ve/alignment.html - // Warning: not thread safe! - Packet16uc MSQ, LSQ, edges; - Packet16uc edgeAlign, align; - - MSQ = vec_ld(0, (unsigned char *)to); // most significant quadword - LSQ = vec_ld(15, (unsigned char *)to); // least significant quadword - edgeAlign = vec_lvsl(0, to); // permute map to extract edges - edges=vec_perm(LSQ, MSQ, edgeAlign); // extract the edges - align = vec_lvsr( 0, to ); // permute map to misalign data - MSQ = vec_perm(edges, (Packet16uc) from, align); // misalign the data (MSQ) - LSQ = vec_perm((Packet16uc) from, edges, align); // misalign the data (LSQ) - vec_st( LSQ, 15, (unsigned char *)to ); // Store the LSQ part first - vec_st( MSQ, 0, (unsigned char *)to ); // Store the MSQ part -} - -template<> EIGEN_STRONG_INLINE void prefetch(const float* addr) { vec_dstt(addr, DST_CTRL(2,2,32), DST_CHAN); } -template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { vec_dstt(addr, DST_CTRL(2,2,32), DST_CHAN); } - -template<> EIGEN_STRONG_INLINE float pfirst(const Packet4f& a) { float EIGEN_ALIGN16 x[4]; vec_st(a, 0, x); return x[0]; } -template<> EIGEN_STRONG_INLINE int pfirst(const Packet4i& a) { int EIGEN_ALIGN16 x[4]; vec_st(a, 0, x); return x[0]; } - -template<> EIGEN_STRONG_INLINE Packet4f preverse(const Packet4f& a) { return (Packet4f)vec_perm((Packet16uc)a,(Packet16uc)a, p16uc_REVERSE); } -template<> EIGEN_STRONG_INLINE Packet4i preverse(const Packet4i& a) { return (Packet4i)vec_perm((Packet16uc)a,(Packet16uc)a, p16uc_REVERSE); } - -template<> EIGEN_STRONG_INLINE Packet4f pabs(const Packet4f& a) { return vec_abs(a); } -template<> EIGEN_STRONG_INLINE Packet4i pabs(const Packet4i& a) { return vec_abs(a); } - -template<> EIGEN_STRONG_INLINE float predux(const Packet4f& a) -{ - Packet4f b, sum; - b = (Packet4f) vec_sld(a, a, 8); - sum = vec_add(a, b); - b = (Packet4f) vec_sld(sum, sum, 4); - sum = vec_add(sum, b); - return pfirst(sum); -} - -template<> EIGEN_STRONG_INLINE Packet4f preduxp(const Packet4f* vecs) -{ - Packet4f v[4], sum[4]; - - // It's easier and faster to transpose then add as columns - // Check: http://www.freevec.org/function/matrix_4x4_transpose_floats for explanation - // Do the transpose, first set of moves - v[0] = vec_mergeh(vecs[0], vecs[2]); - v[1] = vec_mergel(vecs[0], vecs[2]); - v[2] = vec_mergeh(vecs[1], vecs[3]); - v[3] = vec_mergel(vecs[1], vecs[3]); - // Get the resulting vectors - sum[0] = vec_mergeh(v[0], v[2]); - sum[1] = vec_mergel(v[0], v[2]); - sum[2] = vec_mergeh(v[1], v[3]); - sum[3] = vec_mergel(v[1], v[3]); - - // Now do the summation: - // Lines 0+1 - sum[0] = vec_add(sum[0], sum[1]); - // Lines 2+3 - sum[1] = vec_add(sum[2], sum[3]); - // Add the results - sum[0] = vec_add(sum[0], sum[1]); - - return sum[0]; -} - -template<> EIGEN_STRONG_INLINE int predux(const Packet4i& a) -{ - Packet4i sum; - sum = vec_sums(a, p4i_ZERO); - sum = vec_sld(sum, p4i_ZERO, 12); - return pfirst(sum); -} - -template<> EIGEN_STRONG_INLINE Packet4i preduxp(const Packet4i* vecs) -{ - Packet4i v[4], sum[4]; - - // It's easier and faster to transpose then add as columns - // Check: http://www.freevec.org/function/matrix_4x4_transpose_floats for explanation - // Do the transpose, first set of moves - v[0] = vec_mergeh(vecs[0], vecs[2]); - v[1] = vec_mergel(vecs[0], vecs[2]); - v[2] = vec_mergeh(vecs[1], vecs[3]); - v[3] = vec_mergel(vecs[1], vecs[3]); - // Get the resulting vectors - sum[0] = vec_mergeh(v[0], v[2]); - sum[1] = vec_mergel(v[0], v[2]); - sum[2] = vec_mergeh(v[1], v[3]); - sum[3] = vec_mergel(v[1], v[3]); - - // Now do the summation: - // Lines 0+1 - sum[0] = vec_add(sum[0], sum[1]); - // Lines 2+3 - sum[1] = vec_add(sum[2], sum[3]); - // Add the results - sum[0] = vec_add(sum[0], sum[1]); - - return sum[0]; -} - -// Other reduction functions: -// mul -template<> EIGEN_STRONG_INLINE float predux_mul(const Packet4f& a) -{ - Packet4f prod; - prod = pmul(a, (Packet4f)vec_sld(a, a, 8)); - return pfirst(pmul(prod, (Packet4f)vec_sld(prod, prod, 4))); -} - -template<> EIGEN_STRONG_INLINE int predux_mul(const Packet4i& a) -{ - EIGEN_ALIGN16 int aux[4]; - pstore(aux, a); - return aux[0] * aux[1] * aux[2] * aux[3]; -} - -// min -template<> EIGEN_STRONG_INLINE float predux_min(const Packet4f& a) -{ - Packet4f b, res; - b = vec_min(a, vec_sld(a, a, 8)); - res = vec_min(b, vec_sld(b, b, 4)); - return pfirst(res); -} - -template<> EIGEN_STRONG_INLINE int predux_min(const Packet4i& a) -{ - Packet4i b, res; - b = vec_min(a, vec_sld(a, a, 8)); - res = vec_min(b, vec_sld(b, b, 4)); - return pfirst(res); -} - -// max -template<> EIGEN_STRONG_INLINE float predux_max(const Packet4f& a) -{ - Packet4f b, res; - b = vec_max(a, vec_sld(a, a, 8)); - res = vec_max(b, vec_sld(b, b, 4)); - return pfirst(res); -} - -template<> EIGEN_STRONG_INLINE int predux_max(const Packet4i& a) -{ - Packet4i b, res; - b = vec_max(a, vec_sld(a, a, 8)); - res = vec_max(b, vec_sld(b, b, 4)); - return pfirst(res); -} - -template -struct palign_impl -{ - static EIGEN_STRONG_INLINE void run(Packet4f& first, const Packet4f& second) - { - if (Offset!=0) - first = vec_sld(first, second, Offset*4); - } -}; - -template -struct palign_impl -{ - static EIGEN_STRONG_INLINE void run(Packet4i& first, const Packet4i& second) - { - if (Offset!=0) - first = vec_sld(first, second, Offset*4); - } -}; - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_PACKET_MATH_ALTIVEC_H diff --git a/splinter/src/Core/arch/NEON/Complex.h b/splinter/src/Core/arch/NEON/Complex.h deleted file mode 100644 index 8d9255eef6..0000000000 --- a/splinter/src/Core/arch/NEON/Complex.h +++ /dev/null @@ -1,253 +0,0 @@ -// 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_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); -static uint32x2_t p2ui_CONJ_XOR = EIGEN_INIT_NEON_PACKET2(0x00000000, 0x80000000); - -//---------- float ---------- -struct Packet2cf -{ - EIGEN_STRONG_INLINE Packet2cf() {} - EIGEN_STRONG_INLINE explicit Packet2cf(const Packet4f& a) : v(a) {} - Packet4f v; -}; - -template<> struct packet_traits > : default_packet_traits -{ - typedef Packet2cf type; - enum { - Vectorizable = 1, - AlignedOnScalar = 1, - size = 2, - - HasAdd = 1, - HasSub = 1, - HasMul = 1, - HasDiv = 1, - HasNegate = 1, - HasAbs = 0, - HasAbs2 = 0, - HasMin = 0, - HasMax = 0, - HasSetLinear = 0 - }; -}; - -template<> struct unpacket_traits { typedef std::complex type; enum {size=2}; }; - -template<> EIGEN_STRONG_INLINE Packet2cf pset1(const std::complex& from) -{ - float32x2_t r64; - r64 = vld1_f32((float *)&from); - - return Packet2cf(vcombine_f32(r64, r64)); -} - -template<> EIGEN_STRONG_INLINE Packet2cf padd(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(padd(a.v,b.v)); } -template<> EIGEN_STRONG_INLINE Packet2cf psub(const Packet2cf& a, const Packet2cf& b) { return Packet2cf(psub(a.v,b.v)); } -template<> EIGEN_STRONG_INLINE Packet2cf pnegate(const Packet2cf& a) { return Packet2cf(pnegate(a.v)); } -template<> EIGEN_STRONG_INLINE Packet2cf pconj(const Packet2cf& a) -{ - Packet4ui b = vreinterpretq_u32_f32(a.v); - return Packet2cf(vreinterpretq_f32_u32(veorq_u32(b, p4ui_CONJ_XOR))); -} - -template<> EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, const Packet2cf& b) -{ - Packet4f v1, v2; - - // Get the real values of a | a1_re | a1_re | a2_re | a2_re | - v1 = vcombine_f32(vdup_lane_f32(vget_low_f32(a.v), 0), vdup_lane_f32(vget_high_f32(a.v), 0)); - // Get the real values of a | a1_im | a1_im | a2_im | a2_im | - v2 = vcombine_f32(vdup_lane_f32(vget_low_f32(a.v), 1), vdup_lane_f32(vget_high_f32(a.v), 1)); - // Multiply the real a with b - v1 = vmulq_f32(v1, b.v); - // Multiply the imag a with b - v2 = vmulq_f32(v2, b.v); - // Conjugate v2 - v2 = vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(v2), p4ui_CONJ_XOR)); - // Swap real/imag elements in v2. - v2 = vrev64q_f32(v2); - // Add and return the result - return Packet2cf(vaddq_f32(v1, v2)); -} - -template<> EIGEN_STRONG_INLINE Packet2cf pand (const Packet2cf& a, const Packet2cf& b) -{ - return Packet2cf(vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(a.v),vreinterpretq_u32_f32(b.v)))); -} -template<> EIGEN_STRONG_INLINE Packet2cf por (const Packet2cf& a, const Packet2cf& b) -{ - return Packet2cf(vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(a.v),vreinterpretq_u32_f32(b.v)))); -} -template<> EIGEN_STRONG_INLINE Packet2cf pxor (const Packet2cf& a, const Packet2cf& b) -{ - return Packet2cf(vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(a.v),vreinterpretq_u32_f32(b.v)))); -} -template<> EIGEN_STRONG_INLINE Packet2cf pandnot(const Packet2cf& a, const Packet2cf& b) -{ - return Packet2cf(vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(a.v),vreinterpretq_u32_f32(b.v)))); -} - -template<> EIGEN_STRONG_INLINE Packet2cf pload(const std::complex* from) { EIGEN_DEBUG_ALIGNED_LOAD return Packet2cf(pload((const float*)from)); } -template<> EIGEN_STRONG_INLINE Packet2cf ploadu(const std::complex* from) { EIGEN_DEBUG_UNALIGNED_LOAD return Packet2cf(ploadu((const float*)from)); } - -template<> EIGEN_STRONG_INLINE Packet2cf ploaddup(const std::complex* from) { return pset1(*from); } - -template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet2cf& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((float*)to, from.v); } -template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet2cf& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((float*)to, from.v); } - -template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { EIGEN_ARM_PREFETCH((float *)addr); } - -template<> EIGEN_STRONG_INLINE std::complex pfirst(const Packet2cf& a) -{ - std::complex EIGEN_ALIGN16 x[2]; - vst1q_f32((float *)x, a.v); - return x[0]; -} - -template<> EIGEN_STRONG_INLINE Packet2cf preverse(const Packet2cf& a) -{ - float32x2_t a_lo, a_hi; - Packet4f a_r128; - - a_lo = vget_low_f32(a.v); - a_hi = vget_high_f32(a.v); - a_r128 = vcombine_f32(a_hi, a_lo); - - return Packet2cf(a_r128); -} - -template<> EIGEN_STRONG_INLINE Packet2cf pcplxflip(const Packet2cf& a) -{ - return Packet2cf(vrev64q_f32(a.v)); -} - -template<> EIGEN_STRONG_INLINE std::complex predux(const Packet2cf& a) -{ - float32x2_t a1, a2; - std::complex s; - - a1 = vget_low_f32(a.v); - a2 = vget_high_f32(a.v); - a2 = vadd_f32(a1, a2); - vst1_f32((float *)&s, a2); - - return s; -} - -template<> EIGEN_STRONG_INLINE Packet2cf preduxp(const Packet2cf* vecs) -{ - Packet4f sum1, sum2, sum; - - // Add the first two 64-bit float32x2_t of vecs[0] - sum1 = vcombine_f32(vget_low_f32(vecs[0].v), vget_low_f32(vecs[1].v)); - sum2 = vcombine_f32(vget_high_f32(vecs[0].v), vget_high_f32(vecs[1].v)); - sum = vaddq_f32(sum1, sum2); - - return Packet2cf(sum); -} - -template<> EIGEN_STRONG_INLINE std::complex predux_mul(const Packet2cf& a) -{ - float32x2_t a1, a2, v1, v2, prod; - std::complex s; - - a1 = vget_low_f32(a.v); - a2 = vget_high_f32(a.v); - // Get the real values of a | a1_re | a1_re | a2_re | a2_re | - v1 = vdup_lane_f32(a1, 0); - // Get the real values of a | a1_im | a1_im | a2_im | a2_im | - v2 = vdup_lane_f32(a1, 1); - // Multiply the real a with b - v1 = vmul_f32(v1, a2); - // Multiply the imag a with b - v2 = vmul_f32(v2, a2); - // Conjugate v2 - v2 = vreinterpret_f32_u32(veor_u32(vreinterpret_u32_f32(v2), p2ui_CONJ_XOR)); - // Swap real/imag elements in v2. - v2 = vrev64_f32(v2); - // Add v1, v2 - prod = vadd_f32(v1, v2); - - vst1_f32((float *)&s, prod); - - return s; -} - -template -struct palign_impl -{ - EIGEN_STRONG_INLINE static void run(Packet2cf& first, const Packet2cf& second) - { - if (Offset==1) - { - first.v = vextq_f32(first.v, second.v, 2); - } - } -}; - -template<> struct conj_helper -{ - EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet2cf& x, const Packet2cf& y, const Packet2cf& c) const - { return padd(pmul(x,y),c); } - - EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, const Packet2cf& b) const - { - return internal::pmul(a, pconj(b)); - } -}; - -template<> struct conj_helper -{ - EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet2cf& x, const Packet2cf& y, const Packet2cf& c) const - { return padd(pmul(x,y),c); } - - EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, const Packet2cf& b) const - { - return internal::pmul(pconj(a), b); - } -}; - -template<> struct conj_helper -{ - EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet2cf& x, const Packet2cf& y, const Packet2cf& c) const - { return padd(pmul(x,y),c); } - - EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, const Packet2cf& b) const - { - return pconj(internal::pmul(a, b)); - } -}; - -template<> EIGEN_STRONG_INLINE Packet2cf pdiv(const Packet2cf& a, const Packet2cf& b) -{ - // TODO optimize it for AltiVec - Packet2cf res = conj_helper().pmul(a,b); - Packet4f s, rev_s; - - // this computes the norm - s = vmulq_f32(b.v, b.v); - rev_s = vrev64q_f32(s); - - return Packet2cf(pdiv(res.v, vaddq_f32(s,rev_s))); -} - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_COMPLEX_NEON_H diff --git a/splinter/src/Core/arch/NEON/PacketMath.h b/splinter/src/Core/arch/NEON/PacketMath.h deleted file mode 100644 index d49670e041..0000000000 --- a/splinter/src/Core/arch/NEON/PacketMath.h +++ /dev/null @@ -1,420 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2010 Konstantinos Margaritis -// Heavily based on Gael's SSE version. -// -// 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 -#define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 8 -#endif - -// FIXME NEON has 16 quad registers, but since the current register allocator -// is so bad, it is much better to reduce it to 8 -#ifndef EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS -#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 8 -#endif - -typedef float32x4_t Packet4f; -typedef int32x4_t Packet4i; -typedef uint32x4_t Packet4ui; - -#define _EIGEN_DECLARE_CONST_Packet4f(NAME,X) \ - const Packet4f p4f_##NAME = pset1(X) - -#define _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(NAME,X) \ - const Packet4f p4f_##NAME = vreinterpretq_f32_u32(pset1(X)) - -#define _EIGEN_DECLARE_CONST_Packet4i(NAME,X) \ - const Packet4i p4i_##NAME = pset1(X) - -#if defined(__llvm__) && !defined(__clang__) - //Special treatment for Apple's llvm-gcc, its NEON packet types are unions - #define EIGEN_INIT_NEON_PACKET2(X, Y) {{X, Y}} - #define EIGEN_INIT_NEON_PACKET4(X, Y, Z, W) {{X, Y, Z, W}} -#else - //Default initializer for packets - #define EIGEN_INIT_NEON_PACKET2(X, Y) {X, Y} - #define EIGEN_INIT_NEON_PACKET4(X, Y, Z, W) {X, Y, Z, W} -#endif - -// arm64 does have the pld instruction. If available, let's trust the __builtin_prefetch built-in function -// which available on LLVM and GCC (at least) -#if EIGEN_HAS_BUILTIN(__builtin_prefetch) || defined(__GNUC__) - #define EIGEN_ARM_PREFETCH(ADDR) __builtin_prefetch(ADDR); -#elif defined __pld - #define EIGEN_ARM_PREFETCH(ADDR) __pld(ADDR) -#elif !defined(__aarch64__) - #define EIGEN_ARM_PREFETCH(ADDR) __asm__ __volatile__ ( " pld [%[addr]]\n" :: [addr] "r" (ADDR) : "cc" ); -#else - // by default no explicit prefetching - #define EIGEN_ARM_PREFETCH(ADDR) -#endif - -template<> struct packet_traits : default_packet_traits -{ - typedef Packet4f type; - enum { - Vectorizable = 1, - AlignedOnScalar = 1, - size = 4, - - HasDiv = 1, - // FIXME check the Has* - HasSin = 0, - HasCos = 0, - HasLog = 0, - HasExp = 0, - HasSqrt = 0 - }; -}; -template<> struct packet_traits : default_packet_traits -{ - typedef Packet4i type; - enum { - Vectorizable = 1, - AlignedOnScalar = 1, - size=4 - // FIXME check the Has* - }; -}; - -#if EIGEN_GNUC_AT_MOST(4,4) && !defined(__llvm__) -// workaround gcc 4.2, 4.3 and 4.4 compilatin issue -EIGEN_STRONG_INLINE float32x4_t vld1q_f32(const float* x) { return ::vld1q_f32((const float32_t*)x); } -EIGEN_STRONG_INLINE float32x2_t vld1_f32 (const float* x) { return ::vld1_f32 ((const float32_t*)x); } -EIGEN_STRONG_INLINE void vst1q_f32(float* to, float32x4_t from) { ::vst1q_f32((float32_t*)to,from); } -EIGEN_STRONG_INLINE void vst1_f32 (float* to, float32x2_t from) { ::vst1_f32 ((float32_t*)to,from); } -#endif - -template<> struct unpacket_traits { typedef float type; enum {size=4}; }; -template<> struct unpacket_traits { typedef int type; enum {size=4}; }; - -template<> EIGEN_STRONG_INLINE Packet4f pset1(const float& from) { return vdupq_n_f32(from); } -template<> EIGEN_STRONG_INLINE Packet4i pset1(const int& from) { return vdupq_n_s32(from); } - -template<> EIGEN_STRONG_INLINE Packet4f plset(const float& a) -{ - Packet4f countdown = EIGEN_INIT_NEON_PACKET4(0, 1, 2, 3); - return vaddq_f32(pset1(a), countdown); -} -template<> EIGEN_STRONG_INLINE Packet4i plset(const int& a) -{ - Packet4i countdown = EIGEN_INIT_NEON_PACKET4(0, 1, 2, 3); - return vaddq_s32(pset1(a), countdown); -} - -template<> EIGEN_STRONG_INLINE Packet4f padd(const Packet4f& a, const Packet4f& b) { return vaddq_f32(a,b); } -template<> EIGEN_STRONG_INLINE Packet4i padd(const Packet4i& a, const Packet4i& b) { return vaddq_s32(a,b); } - -template<> EIGEN_STRONG_INLINE Packet4f psub(const Packet4f& a, const Packet4f& b) { return vsubq_f32(a,b); } -template<> EIGEN_STRONG_INLINE Packet4i psub(const Packet4i& a, const Packet4i& b) { return vsubq_s32(a,b); } - -template<> EIGEN_STRONG_INLINE Packet4f pnegate(const Packet4f& a) { return vnegq_f32(a); } -template<> EIGEN_STRONG_INLINE Packet4i pnegate(const Packet4i& a) { return vnegq_s32(a); } - -template<> EIGEN_STRONG_INLINE Packet4f pconj(const Packet4f& a) { return a; } -template<> EIGEN_STRONG_INLINE Packet4i pconj(const Packet4i& a) { return a; } - -template<> EIGEN_STRONG_INLINE Packet4f pmul(const Packet4f& a, const Packet4f& b) { return vmulq_f32(a,b); } -template<> EIGEN_STRONG_INLINE Packet4i pmul(const Packet4i& a, const Packet4i& b) { return vmulq_s32(a,b); } - -template<> EIGEN_STRONG_INLINE Packet4f pdiv(const Packet4f& a, const Packet4f& b) -{ - Packet4f inv, restep, div; - - // NEON does not offer a divide instruction, we have to do a reciprocal approximation - // However NEON in contrast to other SIMD engines (AltiVec/SSE), offers - // a reciprocal estimate AND a reciprocal step -which saves a few instructions - // vrecpeq_f32() returns an estimate to 1/b, which we will finetune with - // Newton-Raphson and vrecpsq_f32() - inv = vrecpeq_f32(b); - - // This returns a differential, by which we will have to multiply inv to get a better - // approximation of 1/b. - restep = vrecpsq_f32(b, inv); - inv = vmulq_f32(restep, inv); - - // Finally, multiply a by 1/b and get the wanted result of the division. - div = vmulq_f32(a, inv); - - return div; -} -template<> EIGEN_STRONG_INLINE Packet4i pdiv(const Packet4i& /*a*/, const Packet4i& /*b*/) -{ eigen_assert(false && "packet integer division are not supported by NEON"); - return pset1(0); -} - -// for some weird raisons, it has to be overloaded for packet of integers -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); } - -template<> EIGEN_STRONG_INLINE Packet4f pmax(const Packet4f& a, const Packet4f& b) { return vmaxq_f32(a,b); } -template<> EIGEN_STRONG_INLINE Packet4i pmax(const Packet4i& a, const Packet4i& b) { return vmaxq_s32(a,b); } - -// Logical Operations are not supported for float, so we have to reinterpret casts using NEON intrinsics -template<> EIGEN_STRONG_INLINE Packet4f pand(const Packet4f& a, const Packet4f& b) -{ - return vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(a),vreinterpretq_u32_f32(b))); -} -template<> EIGEN_STRONG_INLINE Packet4i pand(const Packet4i& a, const Packet4i& b) { return vandq_s32(a,b); } - -template<> EIGEN_STRONG_INLINE Packet4f por(const Packet4f& a, const Packet4f& b) -{ - return vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(a),vreinterpretq_u32_f32(b))); -} -template<> EIGEN_STRONG_INLINE Packet4i por(const Packet4i& a, const Packet4i& b) { return vorrq_s32(a,b); } - -template<> EIGEN_STRONG_INLINE Packet4f pxor(const Packet4f& a, const Packet4f& b) -{ - return vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(a),vreinterpretq_u32_f32(b))); -} -template<> EIGEN_STRONG_INLINE Packet4i pxor(const Packet4i& a, const Packet4i& b) { return veorq_s32(a,b); } - -template<> EIGEN_STRONG_INLINE Packet4f pandnot(const Packet4f& a, const Packet4f& b) -{ - return vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(a),vreinterpretq_u32_f32(b))); -} -template<> EIGEN_STRONG_INLINE Packet4i pandnot(const Packet4i& a, const Packet4i& b) { return vbicq_s32(a,b); } - -template<> EIGEN_STRONG_INLINE Packet4f pload(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD return vld1q_f32(from); } -template<> EIGEN_STRONG_INLINE Packet4i pload(const int* from) { EIGEN_DEBUG_ALIGNED_LOAD return vld1q_s32(from); } - -template<> EIGEN_STRONG_INLINE Packet4f ploadu(const float* from) { EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_f32(from); } -template<> EIGEN_STRONG_INLINE Packet4i ploadu(const int* from) { EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_s32(from); } - -template<> EIGEN_STRONG_INLINE Packet4f ploaddup(const float* from) -{ - float32x2_t lo, hi; - lo = vld1_dup_f32(from); - hi = vld1_dup_f32(from+1); - return vcombine_f32(lo, hi); -} -template<> EIGEN_STRONG_INLINE Packet4i ploaddup(const int* from) -{ - int32x2_t lo, hi; - lo = vld1_dup_s32(from); - hi = vld1_dup_s32(from+1); - return vcombine_s32(lo, hi); -} - -template<> EIGEN_STRONG_INLINE void pstore(float* to, const Packet4f& from) { EIGEN_DEBUG_ALIGNED_STORE vst1q_f32(to, from); } -template<> EIGEN_STRONG_INLINE void pstore(int* to, const Packet4i& from) { EIGEN_DEBUG_ALIGNED_STORE vst1q_s32(to, from); } - -template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet4f& from) { EIGEN_DEBUG_UNALIGNED_STORE vst1q_f32(to, from); } -template<> EIGEN_STRONG_INLINE void pstoreu(int* to, const Packet4i& from) { EIGEN_DEBUG_UNALIGNED_STORE vst1q_s32(to, from); } - -template<> EIGEN_STRONG_INLINE void prefetch(const float* addr) { EIGEN_ARM_PREFETCH(addr); } -template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { EIGEN_ARM_PREFETCH(addr); } - -// FIXME only store the 2 first elements ? -template<> EIGEN_STRONG_INLINE float pfirst(const Packet4f& a) { float EIGEN_ALIGN16 x[4]; vst1q_f32(x, a); return x[0]; } -template<> EIGEN_STRONG_INLINE int pfirst(const Packet4i& a) { int EIGEN_ALIGN16 x[4]; vst1q_s32(x, a); return x[0]; } - -template<> EIGEN_STRONG_INLINE Packet4f preverse(const Packet4f& a) { - float32x2_t a_lo, a_hi; - Packet4f a_r64; - - a_r64 = vrev64q_f32(a); - a_lo = vget_low_f32(a_r64); - a_hi = vget_high_f32(a_r64); - return vcombine_f32(a_hi, a_lo); -} -template<> EIGEN_STRONG_INLINE Packet4i preverse(const Packet4i& a) { - int32x2_t a_lo, a_hi; - Packet4i a_r64; - - a_r64 = vrev64q_s32(a); - a_lo = vget_low_s32(a_r64); - a_hi = vget_high_s32(a_r64); - return vcombine_s32(a_hi, a_lo); -} -template<> EIGEN_STRONG_INLINE Packet4f pabs(const Packet4f& a) { return vabsq_f32(a); } -template<> EIGEN_STRONG_INLINE Packet4i pabs(const Packet4i& a) { return vabsq_s32(a); } - -template<> EIGEN_STRONG_INLINE float predux(const Packet4f& a) -{ - float32x2_t a_lo, a_hi, sum; - - a_lo = vget_low_f32(a); - a_hi = vget_high_f32(a); - sum = vpadd_f32(a_lo, a_hi); - sum = vpadd_f32(sum, sum); - return vget_lane_f32(sum, 0); -} - -template<> EIGEN_STRONG_INLINE Packet4f preduxp(const Packet4f* vecs) -{ - float32x4x2_t vtrn1, vtrn2, res1, res2; - Packet4f sum1, sum2, sum; - - // NEON zip performs interleaving of the supplied vectors. - // We perform two interleaves in a row to acquire the transposed vector - vtrn1 = vzipq_f32(vecs[0], vecs[2]); - vtrn2 = vzipq_f32(vecs[1], vecs[3]); - res1 = vzipq_f32(vtrn1.val[0], vtrn2.val[0]); - res2 = vzipq_f32(vtrn1.val[1], vtrn2.val[1]); - - // Do the addition of the resulting vectors - sum1 = vaddq_f32(res1.val[0], res1.val[1]); - sum2 = vaddq_f32(res2.val[0], res2.val[1]); - sum = vaddq_f32(sum1, sum2); - - return sum; -} - -template<> EIGEN_STRONG_INLINE int predux(const Packet4i& a) -{ - int32x2_t a_lo, a_hi, sum; - - a_lo = vget_low_s32(a); - a_hi = vget_high_s32(a); - sum = vpadd_s32(a_lo, a_hi); - sum = vpadd_s32(sum, sum); - return vget_lane_s32(sum, 0); -} - -template<> EIGEN_STRONG_INLINE Packet4i preduxp(const Packet4i* vecs) -{ - int32x4x2_t vtrn1, vtrn2, res1, res2; - Packet4i sum1, sum2, sum; - - // NEON zip performs interleaving of the supplied vectors. - // We perform two interleaves in a row to acquire the transposed vector - vtrn1 = vzipq_s32(vecs[0], vecs[2]); - vtrn2 = vzipq_s32(vecs[1], vecs[3]); - res1 = vzipq_s32(vtrn1.val[0], vtrn2.val[0]); - res2 = vzipq_s32(vtrn1.val[1], vtrn2.val[1]); - - // Do the addition of the resulting vectors - sum1 = vaddq_s32(res1.val[0], res1.val[1]); - sum2 = vaddq_s32(res2.val[0], res2.val[1]); - sum = vaddq_s32(sum1, sum2); - - return sum; -} - -// Other reduction functions: -// mul -template<> EIGEN_STRONG_INLINE float predux_mul(const Packet4f& a) -{ - float32x2_t a_lo, a_hi, prod; - - // Get a_lo = |a1|a2| and a_hi = |a3|a4| - a_lo = vget_low_f32(a); - a_hi = vget_high_f32(a); - // Get the product of a_lo * a_hi -> |a1*a3|a2*a4| - prod = vmul_f32(a_lo, a_hi); - // Multiply prod with its swapped value |a2*a4|a1*a3| - prod = vmul_f32(prod, vrev64_f32(prod)); - - return vget_lane_f32(prod, 0); -} -template<> EIGEN_STRONG_INLINE int predux_mul(const Packet4i& a) -{ - int32x2_t a_lo, a_hi, prod; - - // Get a_lo = |a1|a2| and a_hi = |a3|a4| - a_lo = vget_low_s32(a); - a_hi = vget_high_s32(a); - // Get the product of a_lo * a_hi -> |a1*a3|a2*a4| - prod = vmul_s32(a_lo, a_hi); - // Multiply prod with its swapped value |a2*a4|a1*a3| - prod = vmul_s32(prod, vrev64_s32(prod)); - - return vget_lane_s32(prod, 0); -} - -// min -template<> EIGEN_STRONG_INLINE float predux_min(const Packet4f& a) -{ - float32x2_t a_lo, a_hi, min; - - a_lo = vget_low_f32(a); - a_hi = vget_high_f32(a); - min = vpmin_f32(a_lo, a_hi); - min = vpmin_f32(min, min); - - return vget_lane_f32(min, 0); -} - -template<> EIGEN_STRONG_INLINE int predux_min(const Packet4i& a) -{ - int32x2_t a_lo, a_hi, min; - - a_lo = vget_low_s32(a); - a_hi = vget_high_s32(a); - min = vpmin_s32(a_lo, a_hi); - min = vpmin_s32(min, min); - - return vget_lane_s32(min, 0); -} - -// max -template<> EIGEN_STRONG_INLINE float predux_max(const Packet4f& a) -{ - float32x2_t a_lo, a_hi, max; - - a_lo = vget_low_f32(a); - a_hi = vget_high_f32(a); - max = vpmax_f32(a_lo, a_hi); - max = vpmax_f32(max, max); - - return vget_lane_f32(max, 0); -} - -template<> EIGEN_STRONG_INLINE int predux_max(const Packet4i& a) -{ - int32x2_t a_lo, a_hi, max; - - a_lo = vget_low_s32(a); - a_hi = vget_high_s32(a); - max = vpmax_s32(a_lo, a_hi); - max = vpmax_s32(max, max); - - return vget_lane_s32(max, 0); -} - -// this PALIGN_NEON business is to work around a bug in LLVM Clang 3.0 causing incorrect compilation errors, -// see bug 347 and this LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=11074 -#define PALIGN_NEON(Offset,Type,Command) \ -template<>\ -struct palign_impl\ -{\ - EIGEN_STRONG_INLINE static void run(Type& first, const Type& second)\ - {\ - if (Offset!=0)\ - first = Command(first, second, Offset);\ - }\ -};\ - -PALIGN_NEON(0,Packet4f,vextq_f32) -PALIGN_NEON(1,Packet4f,vextq_f32) -PALIGN_NEON(2,Packet4f,vextq_f32) -PALIGN_NEON(3,Packet4f,vextq_f32) -PALIGN_NEON(0,Packet4i,vextq_s32) -PALIGN_NEON(1,Packet4i,vextq_s32) -PALIGN_NEON(2,Packet4i,vextq_s32) -PALIGN_NEON(3,Packet4i,vextq_s32) - -#undef PALIGN_NEON - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_PACKET_MATH_NEON_H diff --git a/splinter/src/Core/products/CoeffBasedProduct.h b/splinter/src/Core/products/CoeffBasedProduct.h deleted file mode 100644 index 2a9d65b947..0000000000 --- a/splinter/src/Core/products/CoeffBasedProduct.h +++ /dev/null @@ -1,476 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2008 Benoit Jacob -// 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_COEFFBASED_PRODUCT_H -#define EIGEN_COEFFBASED_PRODUCT_H - -namespace Eigen { - -namespace internal { - -/********************************************************************************* -* Coefficient based product implementation. -* It is designed for the following use cases: -* - small fixed sizes -* - lazy products -*********************************************************************************/ - -/* Since the all the dimensions of the product are small, here we can rely - * on the generic Assign mechanism to evaluate the product per coeff (or packet). - * - * Note that here the inner-loops should always be unrolled. - */ - -template -struct product_coeff_impl; - -template -struct product_packet_impl; - -template -struct traits > -{ - typedef MatrixXpr XprKind; - typedef typename remove_all::type _LhsNested; - typedef typename remove_all::type _RhsNested; - typedef typename scalar_product_traits::ReturnType Scalar; - typedef typename promote_storage_type::StorageKind, - typename traits<_RhsNested>::StorageKind>::ret StorageKind; - 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, - InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(_LhsNested::ColsAtCompileTime, _RhsNested::RowsAtCompileTime), - - MaxRowsAtCompileTime = _LhsNested::MaxRowsAtCompileTime, - MaxColsAtCompileTime = _RhsNested::MaxColsAtCompileTime, - - LhsRowMajor = LhsFlags & RowMajorBit, - RhsRowMajor = RhsFlags & RowMajorBit, - - SameType = is_same::value, - - CanVectorizeRhs = RhsRowMajor && (RhsFlags & PacketAccessBit) - && (ColsAtCompileTime == Dynamic - || ( (ColsAtCompileTime % packet_traits::size) == 0 - && (RhsFlags&AlignedBit) - ) - ), - - CanVectorizeLhs = (!LhsRowMajor) && (LhsFlags & PacketAccessBit) - && (RowsAtCompileTime == Dynamic - || ( (RowsAtCompileTime % packet_traits::size) == 0 - && (LhsFlags&AlignedBit) - ) - ), - - EvalToRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 - : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 - : (RhsRowMajor && !CanVectorizeLhs), - - Flags = ((unsigned int)(LhsFlags | RhsFlags) & HereditaryBits & ~RowMajorBit) - | (EvalToRowMajor ? RowMajorBit : 0) - | NestingFlags - | (LhsFlags & RhsFlags & AlignedBit) - // TODO enable vectorization for mixed types - | (SameType && (CanVectorizeLhs || CanVectorizeRhs) ? PacketAccessBit : 0), - - CoeffReadCost = InnerSize == Dynamic ? Dynamic - : InnerSize == 0 ? 0 - : InnerSize * (NumTraits::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) - + (InnerSize - 1) * NumTraits::AddCost, - - /* CanVectorizeInner deserves special explanation. It does not affect the product flags. It is not used outside - * of Product. If the Product itself is not a packet-access expression, there is still a chance that the inner - * loop of the product might be vectorized. This is the meaning of CanVectorizeInner. Since it doesn't affect - * the Flags, it is safe to make this value depend on ActualPacketAccessBit, that doesn't affect the ABI. - */ - CanVectorizeInner = SameType - && LhsRowMajor - && (!RhsRowMajor) - && (LhsFlags & RhsFlags & ActualPacketAccessBit) - && (LhsFlags & RhsFlags & AlignedBit) - && (InnerSize % packet_traits::size == 0) - }; -}; - -} // end namespace internal - -template -class CoeffBasedProduct - : internal::no_assignment_operator, - public MatrixBase > -{ - public: - - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(CoeffBasedProduct) - typedef typename Base::PlainObject PlainObject; - - private: - - typedef typename internal::traits::_LhsNested _LhsNested; - typedef typename internal::traits::_RhsNested _RhsNested; - - enum { - PacketSize = internal::packet_traits::size, - InnerSize = internal::traits::InnerSize, - Unroll = CoeffReadCost != Dynamic && CoeffReadCost <= EIGEN_UNROLLING_LIMIT, - CanVectorizeInner = internal::traits::CanVectorizeInner - }; - - typedef internal::product_coeff_impl ScalarCoeffImpl; - - typedef CoeffBasedProduct LazyCoeffBasedProductType; - - public: - - inline CoeffBasedProduct(const CoeffBasedProduct& other) - : Base(), m_lhs(other.m_lhs), m_rhs(other.m_rhs) - {} - - template - inline CoeffBasedProduct(const Lhs& lhs, const Rhs& rhs) - : m_lhs(lhs), m_rhs(rhs) - { - // we don't allow taking products of matrices of different real types, as that wouldn't be vectorizable. - // We still allow to mix T and complex. - EIGEN_STATIC_ASSERT((internal::scalar_product_traits::Defined), - 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"); - } - - EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); } - - EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const - { - Scalar res; - ScalarCoeffImpl::run(row, col, m_lhs, m_rhs, res); - return res; - } - - /* Allow index-based non-packet access. It is impossible though to allow index-based packed access, - * which is why we don't set the LinearAccessBit. - */ - EIGEN_STRONG_INLINE const Scalar coeff(Index index) const - { - Scalar res; - const Index row = RowsAtCompileTime == 1 ? 0 : index; - const Index col = RowsAtCompileTime == 1 ? index : 0; - ScalarCoeffImpl::run(row, col, m_lhs, m_rhs, res); - return res; - } - - template - EIGEN_STRONG_INLINE const PacketScalar packet(Index row, Index col) const - { - PacketScalar res; - internal::product_packet_impl - ::run(row, col, m_lhs, m_rhs, res); - return res; - } - - // Implicit conversion to the nested type (trigger the evaluation of the product) - EIGEN_STRONG_INLINE operator const PlainObject& () const - { - m_result.lazyAssign(*this); - return m_result; - } - - const _LhsNested& lhs() const { return m_lhs; } - const _RhsNested& rhs() const { return m_rhs; } - - const Diagonal diagonal() const - { return reinterpret_cast(*this); } - - template - const Diagonal diagonal() const - { return reinterpret_cast(*this); } - - const Diagonal diagonal(Index index) const - { return reinterpret_cast(*this).diagonal(index); } - - protected: - typename internal::add_const_on_value_type::type m_lhs; - typename internal::add_const_on_value_type::type m_rhs; - - mutable PlainObject m_result; -}; - -namespace internal { - -// here we need to overload the nested rule for products -// such that the nested type is a const reference to a plain matrix -template -struct nested, N, PlainObject> -{ - typedef PlainObject const& type; -}; - -/*************************************************************************** -* Normal product .coeff() implementation (with meta-unrolling) -***************************************************************************/ - -/************************************** -*** Scalar path - no vectorization *** -**************************************/ - -template -struct product_coeff_impl -{ - typedef typename Lhs::Index Index; - 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-1) * rhs.coeff(UnrollingIndex-1, col); - } -}; - -template -struct product_coeff_impl -{ - typedef typename Lhs::Index Index; - 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); - } -}; - -template -struct product_coeff_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, RetScalar &res) - { - res = RetScalar(0); - } -}; - -template -struct product_coeff_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar& res) - { - res = (lhs.row(row).transpose().cwiseProduct( rhs.col(col) )).sum(); - } -}; - -/******************************************* -*** Scalar path with inner vectorization *** -*******************************************/ - -template -struct product_coeff_vectorized_unroller -{ - typedef typename Lhs::Index Index; - enum { PacketSize = packet_traits::size }; - 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) )); - } -}; - -template -struct product_coeff_vectorized_unroller<0, Lhs, Rhs, Packet> -{ - typedef typename Lhs::Index Index; - 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)); - } -}; - -template -struct product_coeff_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, RetScalar &res) - { - res = 0; - } -}; - -template -struct product_coeff_impl -{ - typedef typename Lhs::PacketScalar Packet; - typedef typename Lhs::Index Index; - enum { PacketSize = packet_traits::size }; - 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); - res = predux(pres); - } -}; - -template -struct product_coeff_vectorized_dyn_selector -{ - typedef typename Lhs::Index Index; - 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.col(col)).sum(); - } -}; - -// NOTE the 3 following specializations are because taking .col(0) on a vector is a bit slower -// NOTE maybe they are now useless since we have a specialization for Block -template -struct product_coeff_vectorized_dyn_selector -{ - typedef typename Lhs::Index Index; - 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(); - } -}; - -template -struct product_coeff_vectorized_dyn_selector -{ - typedef typename Lhs::Index Index; - 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(); - } -}; - -template -struct product_coeff_vectorized_dyn_selector -{ - typedef typename Lhs::Index Index; - 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(); - } -}; - -template -struct product_coeff_impl -{ - typedef typename Lhs::Index Index; - 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); - } -}; - -/******************* -*** Packet path *** -*******************/ - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - 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-1)), rhs.template packet(UnrollingIndex-1, col), res); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - 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-1), pset1(rhs.coeff(UnrollingIndex-1, col)), res); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - 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)); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - 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))); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Packet &res) - { - res = pset1(0); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Packet &res) - { - res = pset1(0); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res) - { - res = pset1(0); - for(Index i = 0; i < lhs.cols(); ++i) - res = pmadd(pset1(lhs.coeff(row, i)), rhs.template packet(i, col), res); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res) - { - res = pset1(0); - for(Index i = 0; i < lhs.cols(); ++i) - res = pmadd(lhs.template packet(row, i), pset1(rhs.coeff(i, col)), res); - } -}; - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_COEFFBASED_PRODUCT_H diff --git a/splinter/src/Core/products/GeneralBlockPanelKernel.h b/splinter/src/Core/products/GeneralBlockPanelKernel.h deleted file mode 100644 index bcdca5b0d2..0000000000 --- a/splinter/src/Core/products/GeneralBlockPanelKernel.h +++ /dev/null @@ -1,1341 +0,0 @@ -// 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_GENERAL_BLOCK_PANEL_H -#define EIGEN_GENERAL_BLOCK_PANEL_H - -namespace Eigen { - -namespace internal { - -template -class gebp_traits; - - -/** \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; -} - -/** \internal */ -inline void manage_caching_sizes(Action action, std::ptrdiff_t* l1=0, std::ptrdiff_t* l2=0) -{ - 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 - eigen_internal_assert(l1!=0 && l2!=0); - m_l1CacheSize = *l1; - m_l2CacheSize = *l2; - } - else if(action==GetAction) - { - eigen_internal_assert(l1!=0 && l2!=0); - *l1 = m_l1CacheSize; - *l2 = m_l2CacheSize; - } - else - { - eigen_internal_assert(false); - } -} - -/** \brief Computes the blocking parameters for a m x k times k x n matrix product - * - * \param[in,out] k Input: the third dimension of the product. Output: the blocking size along the same dimension. - * \param[in,out] m Input: the number of rows of the left hand side. Output: the blocking size along the same dimension. - * \param[in,out] n Input: the number of columns of the right hand side. Output: the blocking size along the same dimension. - * - * Given a m x k times k x n matrix product of scalar types \c LhsScalar and \c RhsScalar, - * this function computes the blocking size parameters along the respective dimensions - * for matrix products and related algorithms. The blocking sizes depends on various - * parameters: - * - the L1 and L2 cache sizes, - * - the register level blocking sizes defined by gebp_traits, - * - the number of scalars that fit into a packet (when vectorization is enabled). - * - * \sa setCpuCacheSizes */ -template -void computeProductBlockingSizes(SizeType& k, SizeType& m, SizeType& n) -{ - EIGEN_UNUSED_VARIABLE(n); - // Explanations: - // Let's recall the product algorithms form kc x nc horizontal panels B' on the rhs and - // mc x kc blocks A' on the lhs. A' has to fit into L2 cache. Moreover, B' is processed - // per kc x nr vertical small panels where nr is the blocking size along the n dimension - // at the register level. For vectorization purpose, these small vertical panels are unpacked, - // e.g., each coefficient is replicated to fit a packet. This small vertical panel has to - // stay in L1 cache. - std::ptrdiff_t l1, l2; - - typedef gebp_traits Traits; - enum { - kdiv = KcFactor * 2 * Traits::nr - * Traits::RhsProgress * sizeof(RhsScalar), - mr = gebp_traits::mr, - mr_mask = (0xffffffff/mr)*mr - }; - - manage_caching_sizes(GetAction, &l1, &l2); - k = std::min(k, l1/kdiv); - SizeType _m = k>0 ? l2/(4 * sizeof(LhsScalar) * k) : 0; - if(_m -inline void computeProductBlockingSizes(SizeType& k, SizeType& m, SizeType& n) -{ - computeProductBlockingSizes(k, m, n); -} - -#ifdef EIGEN_HAS_FUSE_CJMADD - #define MADD(CJ,A,B,C,T) C = CJ.pmadd(A,B,C); -#else - - // FIXME (a bit overkill maybe ?) - - template struct gebp_madd_selector { - EIGEN_ALWAYS_INLINE static void run(const CJ& cj, A& a, B& b, C& c, T& /*t*/) - { - c = cj.pmadd(a,b,c); - } - }; - - template struct gebp_madd_selector { - EIGEN_ALWAYS_INLINE static void run(const CJ& cj, T& a, T& b, T& c, T& t) - { - t = b; t = cj.pmul(a,t); c = padd(c,t); - } - }; - - template - EIGEN_STRONG_INLINE void gebp_madd(const CJ& cj, A& a, B& b, C& c, T& t) - { - gebp_madd_selector::run(cj,a,b,c,t); - } - - #define MADD(CJ,A,B,C,T) gebp_madd(CJ,A,B,C,T); -// #define MADD(CJ,A,B,C,T) T = B; T = CJ.pmul(A,T); C = padd(C,T); -#endif - -/* Vectorization logic - * real*real: unpack rhs to constant packets, ... - * - * cd*cd : unpack rhs to (b_r,b_r), (b_i,b_i), mul to get (a_r b_r,a_i b_r) (a_r b_i,a_i b_i), - * storing each res packet into two packets (2x2), - * at the end combine them: swap the second and addsub them - * cf*cf : same but with 2x4 blocks - * cplx*real : unpack rhs to constant packets, ... - * real*cplx : load lhs as (a0,a0,a1,a1), and mul as usual - */ -template -class gebp_traits -{ -public: - typedef _LhsScalar LhsScalar; - typedef _RhsScalar RhsScalar; - typedef typename scalar_product_traits::ReturnType ResScalar; - - enum { - ConjLhs = _ConjLhs, - ConjRhs = _ConjRhs, - Vectorizable = packet_traits::Vectorizable && packet_traits::Vectorizable, - LhsPacketSize = Vectorizable ? packet_traits::size : 1, - RhsPacketSize = Vectorizable ? packet_traits::size : 1, - ResPacketSize = Vectorizable ? packet_traits::size : 1, - - NumberOfRegisters = EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS, - - // register block size along the N direction (must be either 2 or 4) - nr = NumberOfRegisters/4, - - // register block size along the M direction (currently, this one cannot be modified) - mr = 2 * LhsPacketSize, - - WorkSpaceFactor = nr * RhsPacketSize, - - LhsProgress = LhsPacketSize, - RhsProgress = RhsPacketSize - }; - - typedef typename packet_traits::type _LhsPacket; - typedef typename packet_traits::type _RhsPacket; - typedef typename packet_traits::type _ResPacket; - - typedef typename conditional::type LhsPacket; - typedef typename conditional::type RhsPacket; - typedef typename conditional::type ResPacket; - - typedef ResPacket AccPacket; - - EIGEN_STRONG_INLINE void initAcc(AccPacket& p) - { - p = pset1(ResScalar(0)); - } - - EIGEN_STRONG_INLINE void unpackRhs(DenseIndex n, const RhsScalar* rhs, RhsScalar* b) - { - for(DenseIndex k=0; k(&b[k*RhsPacketSize], rhs[k]); - } - - EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, RhsPacket& dest) const - { - dest = pload(b); - } - - EIGEN_STRONG_INLINE void loadLhs(const LhsScalar* a, LhsPacket& dest) const - { - dest = pload(a); - } - - EIGEN_STRONG_INLINE void madd(const LhsPacket& a, const RhsPacket& b, AccPacket& c, AccPacket& tmp) const - { - tmp = b; tmp = pmul(a,tmp); c = padd(c,tmp); - } - - EIGEN_STRONG_INLINE void acc(const AccPacket& c, const ResPacket& alpha, ResPacket& r) const - { - r = pmadd(c,alpha,r); - } - -protected: -// conj_helper cj; -// conj_helper pcj; -}; - -template -class gebp_traits, RealScalar, _ConjLhs, false> -{ -public: - typedef std::complex LhsScalar; - typedef RealScalar RhsScalar; - typedef typename scalar_product_traits::ReturnType ResScalar; - - enum { - ConjLhs = _ConjLhs, - ConjRhs = false, - Vectorizable = packet_traits::Vectorizable && packet_traits::Vectorizable, - LhsPacketSize = Vectorizable ? packet_traits::size : 1, - RhsPacketSize = Vectorizable ? packet_traits::size : 1, - ResPacketSize = Vectorizable ? packet_traits::size : 1, - - NumberOfRegisters = EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS, - nr = NumberOfRegisters/4, - mr = 2 * LhsPacketSize, - WorkSpaceFactor = nr*RhsPacketSize, - - LhsProgress = LhsPacketSize, - RhsProgress = RhsPacketSize - }; - - typedef typename packet_traits::type _LhsPacket; - typedef typename packet_traits::type _RhsPacket; - typedef typename packet_traits::type _ResPacket; - - typedef typename conditional::type LhsPacket; - typedef typename conditional::type RhsPacket; - typedef typename conditional::type ResPacket; - - typedef ResPacket AccPacket; - - EIGEN_STRONG_INLINE void initAcc(AccPacket& p) - { - p = pset1(ResScalar(0)); - } - - EIGEN_STRONG_INLINE void unpackRhs(DenseIndex n, const RhsScalar* rhs, RhsScalar* b) - { - for(DenseIndex k=0; k(&b[k*RhsPacketSize], rhs[k]); - } - - EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, RhsPacket& dest) const - { - dest = pload(b); - } - - EIGEN_STRONG_INLINE void loadLhs(const LhsScalar* a, LhsPacket& dest) const - { - dest = pload(a); - } - - EIGEN_STRONG_INLINE void madd(const LhsPacket& a, const RhsPacket& b, AccPacket& c, RhsPacket& tmp) const - { - madd_impl(a, b, c, tmp, typename conditional::type()); - } - - EIGEN_STRONG_INLINE void madd_impl(const LhsPacket& a, const RhsPacket& b, AccPacket& c, RhsPacket& tmp, const true_type&) const - { - tmp = b; tmp = pmul(a.v,tmp); c.v = padd(c.v,tmp); - } - - EIGEN_STRONG_INLINE void madd_impl(const LhsScalar& a, const RhsScalar& b, ResScalar& c, RhsScalar& /*tmp*/, const false_type&) const - { - c += a * b; - } - - EIGEN_STRONG_INLINE void acc(const AccPacket& c, const ResPacket& alpha, ResPacket& r) const - { - r = cj.pmadd(c,alpha,r); - } - -protected: - conj_helper cj; -}; - -template -class gebp_traits, std::complex, _ConjLhs, _ConjRhs > -{ -public: - typedef std::complex Scalar; - typedef std::complex LhsScalar; - typedef std::complex RhsScalar; - typedef std::complex ResScalar; - - enum { - ConjLhs = _ConjLhs, - ConjRhs = _ConjRhs, - Vectorizable = packet_traits::Vectorizable - && packet_traits::Vectorizable, - RealPacketSize = Vectorizable ? packet_traits::size : 1, - ResPacketSize = Vectorizable ? packet_traits::size : 1, - - nr = 2, - mr = 2 * ResPacketSize, - WorkSpaceFactor = Vectorizable ? 2*nr*RealPacketSize : nr, - - LhsProgress = ResPacketSize, - RhsProgress = Vectorizable ? 2*ResPacketSize : 1 - }; - - typedef typename packet_traits::type RealPacket; - typedef typename packet_traits::type ScalarPacket; - struct DoublePacket - { - RealPacket first; - RealPacket second; - }; - - typedef typename conditional::type LhsPacket; - typedef typename conditional::type RhsPacket; - typedef typename conditional::type ResPacket; - typedef typename conditional::type AccPacket; - - EIGEN_STRONG_INLINE void initAcc(Scalar& p) { p = Scalar(0); } - - EIGEN_STRONG_INLINE void initAcc(DoublePacket& p) - { - p.first = pset1(RealScalar(0)); - p.second = pset1(RealScalar(0)); - } - - /* Unpack the rhs coeff such that each complex coefficient is spread into - * two packects containing respectively the real and imaginary coefficient - * duplicated as many time as needed: (x+iy) => [x, ..., x] [y, ..., y] - */ - EIGEN_STRONG_INLINE void unpackRhs(DenseIndex n, const Scalar* rhs, Scalar* b) - { - for(DenseIndex k=0; k((RealScalar*)&b[k*ResPacketSize*2+0], real(rhs[k])); - pstore1((RealScalar*)&b[k*ResPacketSize*2+ResPacketSize], imag(rhs[k])); - } - else - b[k] = rhs[k]; - } - } - - EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, ResPacket& dest) const { dest = *b; } - - EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, DoublePacket& dest) const - { - dest.first = pload((const RealScalar*)b); - dest.second = pload((const RealScalar*)(b+ResPacketSize)); - } - - // nothing special here - EIGEN_STRONG_INLINE void loadLhs(const LhsScalar* a, LhsPacket& dest) const - { - dest = pload((const typename unpacket_traits::type*)(a)); - } - - EIGEN_STRONG_INLINE void madd(const LhsPacket& a, const RhsPacket& b, DoublePacket& c, RhsPacket& /*tmp*/) const - { - c.first = padd(pmul(a,b.first), c.first); - c.second = padd(pmul(a,b.second),c.second); - } - - EIGEN_STRONG_INLINE void madd(const LhsPacket& a, const RhsPacket& b, ResPacket& c, RhsPacket& /*tmp*/) const - { - c = cj.pmadd(a,b,c); - } - - EIGEN_STRONG_INLINE void acc(const Scalar& c, const Scalar& alpha, Scalar& r) const { r += alpha * c; } - - EIGEN_STRONG_INLINE void acc(const DoublePacket& c, const ResPacket& alpha, ResPacket& r) const - { - // assemble c - ResPacket tmp; - if((!ConjLhs)&&(!ConjRhs)) - { - tmp = pcplxflip(pconj(ResPacket(c.second))); - tmp = padd(ResPacket(c.first),tmp); - } - else if((!ConjLhs)&&(ConjRhs)) - { - tmp = pconj(pcplxflip(ResPacket(c.second))); - tmp = padd(ResPacket(c.first),tmp); - } - else if((ConjLhs)&&(!ConjRhs)) - { - tmp = pcplxflip(ResPacket(c.second)); - tmp = padd(pconj(ResPacket(c.first)),tmp); - } - else if((ConjLhs)&&(ConjRhs)) - { - tmp = pcplxflip(ResPacket(c.second)); - tmp = psub(pconj(ResPacket(c.first)),tmp); - } - - r = pmadd(tmp,alpha,r); - } - -protected: - conj_helper cj; -}; - -template -class gebp_traits, false, _ConjRhs > -{ -public: - typedef std::complex Scalar; - typedef RealScalar LhsScalar; - typedef Scalar RhsScalar; - typedef Scalar ResScalar; - - enum { - ConjLhs = false, - ConjRhs = _ConjRhs, - Vectorizable = packet_traits::Vectorizable - && packet_traits::Vectorizable, - LhsPacketSize = Vectorizable ? packet_traits::size : 1, - RhsPacketSize = Vectorizable ? packet_traits::size : 1, - ResPacketSize = Vectorizable ? packet_traits::size : 1, - - NumberOfRegisters = EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS, - nr = 4, - mr = 2*ResPacketSize, - WorkSpaceFactor = nr*RhsPacketSize, - - LhsProgress = ResPacketSize, - RhsProgress = ResPacketSize - }; - - typedef typename packet_traits::type _LhsPacket; - typedef typename packet_traits::type _RhsPacket; - typedef typename packet_traits::type _ResPacket; - - typedef typename conditional::type LhsPacket; - typedef typename conditional::type RhsPacket; - typedef typename conditional::type ResPacket; - - typedef ResPacket AccPacket; - - EIGEN_STRONG_INLINE void initAcc(AccPacket& p) - { - p = pset1(ResScalar(0)); - } - - EIGEN_STRONG_INLINE void unpackRhs(DenseIndex n, const RhsScalar* rhs, RhsScalar* b) - { - for(DenseIndex k=0; k(&b[k*RhsPacketSize], rhs[k]); - } - - EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, RhsPacket& dest) const - { - dest = pload(b); - } - - EIGEN_STRONG_INLINE void loadLhs(const LhsScalar* a, LhsPacket& dest) const - { - dest = ploaddup(a); - } - - EIGEN_STRONG_INLINE void madd(const LhsPacket& a, const RhsPacket& b, AccPacket& c, RhsPacket& tmp) const - { - madd_impl(a, b, c, tmp, typename conditional::type()); - } - - EIGEN_STRONG_INLINE void madd_impl(const LhsPacket& a, const RhsPacket& b, AccPacket& c, RhsPacket& tmp, const true_type&) const - { - tmp = b; tmp.v = pmul(a,tmp.v); c = padd(c,tmp); - } - - EIGEN_STRONG_INLINE void madd_impl(const LhsScalar& a, const RhsScalar& b, ResScalar& c, RhsScalar& /*tmp*/, const false_type&) const - { - c += a * b; - } - - EIGEN_STRONG_INLINE void acc(const AccPacket& c, const ResPacket& alpha, ResPacket& r) const - { - r = cj.pmadd(alpha,c,r); - } - -protected: - conj_helper cj; -}; - -/* optimized GEneral packed Block * packed Panel product kernel - * - * Mixing type logic: C += A * B - * | A | B | comments - * |real |cplx | no vectorization yet, would require to pack A with duplication - * |cplx |real | easy vectorization - */ -template -struct gebp_kernel -{ - typedef gebp_traits Traits; - typedef typename Traits::ResScalar ResScalar; - typedef typename Traits::LhsPacket LhsPacket; - typedef typename Traits::RhsPacket RhsPacket; - typedef typename Traits::ResPacket ResPacket; - typedef typename Traits::AccPacket AccPacket; - - enum { - Vectorizable = Traits::Vectorizable, - LhsProgress = Traits::LhsProgress, - RhsProgress = Traits::RhsProgress, - ResPacketSize = Traits::ResPacketSize - }; - - EIGEN_DONT_INLINE - 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); -}; - -template -EIGEN_DONT_INLINE -void gebp_kernel - ::operator()(ResScalar* res, Index resStride, const LhsScalar* blockA, const RhsScalar* blockB, Index rows, Index depth, Index cols, ResScalar alpha, - Index strideA, Index strideB, Index offsetA, Index offsetB, RhsScalar* unpackedB) - { - Traits traits; - - if(strideA==-1) strideA = depth; - if(strideB==-1) strideB = depth; - conj_helper cj; -// conj_helper pcj; - Index packet_cols = (cols/nr) * nr; - const Index peeled_mc = (rows/mr)*mr; - // FIXME: - const Index peeled_mc2 = peeled_mc + (rows-peeled_mc >= LhsProgress ? LhsProgress : 0); - const Index peeled_kc = (depth/4)*4; - - if(unpackedB==0) - unpackedB = const_cast(blockB - strideB * nr * RhsProgress); - - // loops on each micro vertical panel of rhs (depth x nr) - for(Index j2=0; j2 we select a mr x nr micro block of res which is entirely - // stored into mr/packet_size x nr registers. - for(Index i=0; i(alpha); - - R0 = ploadu(r0); - R1 = ploadu(r1); - R2 = ploadu(r2); - R3 = ploadu(r3); - R4 = ploadu(r0 + ResPacketSize); - R5 = ploadu(r1 + ResPacketSize); - R6 = ploadu(r2 + ResPacketSize); - traits.acc(C0, alphav, R0); - pstoreu(r0, R0); - R0 = ploadu(r3 + ResPacketSize); - - traits.acc(C1, alphav, R1); - traits.acc(C2, alphav, R2); - traits.acc(C3, alphav, R3); - traits.acc(C4, alphav, R4); - traits.acc(C5, alphav, R5); - traits.acc(C6, alphav, R6); - traits.acc(C7, alphav, R0); - - pstoreu(r1, R1); - pstoreu(r2, R2); - pstoreu(r3, R3); - pstoreu(r0 + ResPacketSize, R4); - pstoreu(r1 + ResPacketSize, R5); - pstoreu(r2 + ResPacketSize, R6); - pstoreu(r3 + ResPacketSize, R0); - } - else - { - ResPacket R0, R1, R4; - ResPacket alphav = pset1(alpha); - - R0 = ploadu(r0); - R1 = ploadu(r1); - R4 = ploadu(r0 + ResPacketSize); - traits.acc(C0, alphav, R0); - pstoreu(r0, R0); - R0 = ploadu(r1 + ResPacketSize); - traits.acc(C1, alphav, R1); - traits.acc(C4, alphav, R4); - traits.acc(C5, alphav, R0); - pstoreu(r1, R1); - pstoreu(r0 + ResPacketSize, R4); - pstoreu(r1 + ResPacketSize, R0); - } - - } - - if(rows-peeled_mc>=LhsProgress) - { - Index i = peeled_mc; - const LhsScalar* blA = &blockA[i*strideA+offsetA*LhsProgress]; - prefetch(&blA[0]); - - // gets res block as register - AccPacket C0, C1, C2, C3; - traits.initAcc(C0); - traits.initAcc(C1); - if(nr==4) traits.initAcc(C2); - if(nr==4) traits.initAcc(C3); - - // performs "inner" product - const RhsScalar* blB = unpackedB; - for(Index k=0; k(alpha); - - ResScalar* r0 = &res[(j2+0)*resStride + i]; - ResScalar* r1 = r0 + resStride; - ResScalar* r2 = r1 + resStride; - ResScalar* r3 = r2 + resStride; - - R0 = ploadu(r0); - R1 = ploadu(r1); - if(nr==4) R2 = ploadu(r2); - if(nr==4) R3 = ploadu(r3); - - traits.acc(C0, alphav, R0); - traits.acc(C1, alphav, R1); - if(nr==4) traits.acc(C2, alphav, R2); - if(nr==4) traits.acc(C3, alphav, R3); - - pstoreu(r0, R0); - pstoreu(r1, R1); - if(nr==4) pstoreu(r2, R2); - if(nr==4) pstoreu(r3, R3); - } - for(Index i=peeled_mc2; i do the same but with nr==1 - for(Index j2=packet_cols; j2(alpha); - - ResScalar* r0 = &res[(j2+0)*resStride + i]; - - R0 = ploadu(r0); - R4 = ploadu(r0+ResPacketSize); - - traits.acc(C0, alphav, R0); - traits.acc(C4, alphav, R4); - - pstoreu(r0, R0); - pstoreu(r0+ResPacketSize, R4); - } - if(rows-peeled_mc>=LhsProgress) - { - Index i = peeled_mc; - const LhsScalar* blA = &blockA[i*strideA+offsetA*LhsProgress]; - prefetch(&blA[0]); - - AccPacket C0; - traits.initAcc(C0); - - const RhsScalar* blB = unpackedB; - for(Index k=0; k(alpha); - ResPacket R0 = ploadu(&res[(j2+0)*resStride + i]); - traits.acc(C0, alphav, R0); - pstoreu(&res[(j2+0)*resStride + i], R0); - } - for(Index i=peeled_mc2; i -struct gemm_pack_lhs -{ - EIGEN_DONT_INLINE void operator()(Scalar* blockA, const Scalar* EIGEN_RESTRICT _lhs, Index lhsStride, Index depth, Index rows, Index stride=0, Index offset=0); -}; - -template -EIGEN_DONT_INLINE void gemm_pack_lhs - ::operator()(Scalar* blockA, const Scalar* EIGEN_RESTRICT _lhs, Index lhsStride, Index depth, Index rows, Index stride, Index offset) -{ - typedef typename packet_traits::type Packet; - enum { PacketSize = packet_traits::size }; - - EIGEN_ASM_COMMENT("EIGEN PRODUCT PACK LHS"); - EIGEN_UNUSED_VARIABLE(stride) - EIGEN_UNUSED_VARIABLE(offset) - 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; - Index peeled_mc = (rows/Pack1)*Pack1; - 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) - { - if(PanelMode) count += Pack2*offset; - for(Index k=0; k -struct gemm_pack_rhs -{ - typedef typename packet_traits::type Packet; - enum { PacketSize = packet_traits::size }; - EIGEN_DONT_INLINE void operator()(Scalar* blockB, const Scalar* rhs, Index rhsStride, Index depth, Index cols, Index stride=0, Index offset=0); -}; - -template -EIGEN_DONT_INLINE void gemm_pack_rhs - ::operator()(Scalar* blockB, const Scalar* rhs, Index rhsStride, Index depth, Index cols, Index stride, Index offset) -{ - EIGEN_ASM_COMMENT("EIGEN PRODUCT PACK RHS COLMAJOR"); - EIGEN_UNUSED_VARIABLE(stride) - EIGEN_UNUSED_VARIABLE(offset) - eigen_assert(((!PanelMode) && stride==0 && offset==0) || (PanelMode && stride>=depth && offset<=stride)); - conj_if::IsComplex && Conjugate> cj; - Index packet_cols = (cols/nr) * nr; - Index count = 0; - for(Index j2=0; j2 -struct gemm_pack_rhs -{ - enum { PacketSize = packet_traits::size }; - EIGEN_DONT_INLINE void operator()(Scalar* blockB, const Scalar* rhs, Index rhsStride, Index depth, Index cols, Index stride=0, Index offset=0); -}; - -template -EIGEN_DONT_INLINE void gemm_pack_rhs - ::operator()(Scalar* blockB, const Scalar* rhs, Index rhsStride, Index depth, Index cols, Index stride, Index offset) -{ - EIGEN_ASM_COMMENT("EIGEN PRODUCT PACK RHS ROWMAJOR"); - EIGEN_UNUSED_VARIABLE(stride) - EIGEN_UNUSED_VARIABLE(offset) - eigen_assert(((!PanelMode) && stride==0 && offset==0) || (PanelMode && stride>=depth && offset<=stride)); - conj_if::IsComplex && Conjugate> cj; - Index packet_cols = (cols/nr) * nr; - Index count = 0; - for(Index j2=0; j2 -// -// 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; - -/* Specialization for a row-major destination matrix => simple transposition of the product */ -template< - typename Index, - typename LhsScalar, int LhsStorageOrder, bool ConjugateLhs, - typename RhsScalar, int RhsStorageOrder, bool ConjugateRhs> -struct general_matrix_matrix_product -{ - typedef typename scalar_product_traits::ReturnType ResScalar; - static EIGEN_STRONG_INLINE void run( - Index rows, Index cols, Index depth, - const LhsScalar* lhs, Index lhsStride, - const RhsScalar* rhs, Index rhsStride, - ResScalar* res, Index resStride, - ResScalar alpha, - level3_blocking& blocking, - GemmParallelInfo* info = 0) - { - // transpose the product such that the result is column major - general_matrix_matrix_product - ::run(cols,rows,depth,rhs,rhsStride,lhs,lhsStride,res,resStride,alpha,blocking,info); - } -}; - -/* Specialization for a col-major destination matrix - * => Blocking algorithm following Goto's paper */ -template< - typename Index, - typename LhsScalar, int LhsStorageOrder, bool ConjugateLhs, - typename RhsScalar, int RhsStorageOrder, bool ConjugateRhs> -struct general_matrix_matrix_product -{ - -typedef typename scalar_product_traits::ReturnType ResScalar; -static void run(Index rows, Index cols, Index depth, - const LhsScalar* _lhs, Index lhsStride, - const RhsScalar* _rhs, Index rhsStride, - ResScalar* res, Index resStride, - ResScalar alpha, - level3_blocking& blocking, - GemmParallelInfo* info = 0) -{ - const_blas_data_mapper lhs(_lhs,lhsStride); - const_blas_data_mapper rhs(_rhs,rhsStride); - - typedef gebp_traits Traits; - - 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 - - gemm_pack_lhs pack_lhs; - gemm_pack_rhs pack_rhs; - gebp_kernel gebp; - -#ifdef EIGEN_HAS_OPENMP - if(info) - { - // this is the parallel version! - Index tid = omp_get_thread_num(); - Index threads = omp_get_num_threads(); - - std::size_t sizeA = kc*mc; - std::size_t sizeW = kc*Traits::WorkSpaceFactor; - ei_declare_aligned_stack_constructed_variable(LhsScalar, blockA, sizeA, 0); - ei_declare_aligned_stack_constructed_variable(RhsScalar, w, sizeW, 0); - - RhsScalar* blockB = blocking.blockB(); - eigen_internal_assert(blockB!=0); - - // For each horizontal panel of the rhs, and corresponding vertical panel of the lhs... - for(Index k=0; k rows of B', and cols of the A' - - // In order to reduce the chance that a thread has to wait for the other, - // let's start by packing A'. - pack_lhs(blockA, &lhs(0,k), lhsStride, actual_kc, mc); - - // Pack B_k to B' in a parallel fashion: - // each thread packs the sub block B_k,j to B'_j where j is the thread id. - - // However, before copying to B'_j, we have to make sure that no other thread is still using it, - // i.e., we test that info[tid].users equals 0. - // Then, we set info[tid].users to the number of threads to mark that all other threads are going to use it. - while(info[tid].users!=0) {} - info[tid].users += threads; - - pack_rhs(blockB+info[tid].rhs_start*actual_kc, &rhs(k,info[tid].rhs_start), rhsStride, actual_kc, info[tid].rhs_length); - - // Notify the other threads that the part B'_j is ready to go. - info[tid].sync = k; - - // Computes C_i += A' * B' per B'_j - for(Index shift=0; shift0) - while(info[j].sync!=k) {} - - gebp(res+info[j].rhs_start*resStride, resStride, blockA, blockB+info[j].rhs_start*actual_kc, mc, actual_kc, info[j].rhs_length, alpha, -1,-1,0,0, w); - } - - // Then keep going as usual with the remaining A' - for(Index i=mc; i Pack rhs's panel into a sequential chunk of memory (L2 caching) - // Note that this panel will be read as many times as the number of blocks in the lhs's - // vertical panel which is, in practice, a very low number. - pack_rhs(blockB, &rhs(k2,0), rhsStride, actual_kc, cols); - - // For each mc x kc block of the lhs's vertical panel... - // (==GEPP_VAR1) - for(Index i2=0; i2 for "large" GEMM, i.e., -* implementation of the high level wrapper to general_matrix_matrix_product -**********************************************************************************/ - -template -struct traits > - : traits, Lhs, Rhs> > -{}; - -template -struct gemm_functor -{ - gemm_functor(const Lhs& lhs, const Rhs& rhs, Dest& dest, const Scalar& actualAlpha, - BlockingType& blocking) - : m_lhs(lhs), m_rhs(rhs), m_dest(dest), m_actualAlpha(actualAlpha), m_blocking(blocking) - {} - - void initParallelSession() const - { - m_blocking.allocateB(); - } - - void operator() (Index row, Index rows, Index col=0, Index cols=-1, GemmParallelInfo* info=0) const - { - if(cols==-1) - cols = m_rhs.cols(); - - Gemm::run(rows, cols, m_lhs.cols(), - /*(const Scalar*)*/&m_lhs.coeffRef(row,0), m_lhs.outerStride(), - /*(const Scalar*)*/&m_rhs.coeffRef(0,col), m_rhs.outerStride(), - (Scalar*)&(m_dest.coeffRef(row,col)), m_dest.outerStride(), - m_actualAlpha, m_blocking, info); - } - - protected: - const Lhs& m_lhs; - const Rhs& m_rhs; - Dest& m_dest; - Scalar m_actualAlpha; - BlockingType& m_blocking; -}; - -template class gemm_blocking_space; - -template -class level3_blocking -{ - typedef _LhsScalar LhsScalar; - typedef _RhsScalar RhsScalar; - - protected: - LhsScalar* m_blockA; - RhsScalar* m_blockB; - RhsScalar* m_blockW; - - DenseIndex m_mc; - DenseIndex m_nc; - DenseIndex m_kc; - - public: - - level3_blocking() - : m_blockA(0), m_blockB(0), m_blockW(0), m_mc(0), m_nc(0), m_kc(0) - {} - - inline DenseIndex mc() const { return m_mc; } - inline DenseIndex nc() const { return m_nc; } - inline DenseIndex kc() const { return m_kc; } - - inline LhsScalar* blockA() { return m_blockA; } - inline RhsScalar* blockB() { return m_blockB; } - inline RhsScalar* blockW() { return m_blockW; } -}; - -template -class gemm_blocking_space - : public level3_blocking< - typename conditional::type, - typename conditional::type> -{ - enum { - Transpose = StorageOrder==RowMajor, - ActualRows = Transpose ? MaxCols : MaxRows, - ActualCols = Transpose ? MaxRows : MaxCols - }; - typedef typename conditional::type LhsScalar; - typedef typename conditional::type RhsScalar; - typedef gebp_traits Traits; - enum { - SizeA = ActualRows * MaxDepth, - SizeB = ActualCols * MaxDepth, - SizeW = MaxDepth * Traits::WorkSpaceFactor - }; - - EIGEN_ALIGN16 LhsScalar m_staticA[SizeA]; - EIGEN_ALIGN16 RhsScalar m_staticB[SizeB]; - EIGEN_ALIGN16 RhsScalar m_staticW[SizeW]; - - public: - - gemm_blocking_space(DenseIndex /*rows*/, DenseIndex /*cols*/, DenseIndex /*depth*/) - { - this->m_mc = ActualRows; - this->m_nc = ActualCols; - this->m_kc = MaxDepth; - this->m_blockA = m_staticA; - this->m_blockB = m_staticB; - this->m_blockW = m_staticW; - } - - inline void allocateA() {} - inline void allocateB() {} - inline void allocateW() {} - inline void allocateAll() {} -}; - -template -class gemm_blocking_space - : public level3_blocking< - typename conditional::type, - typename conditional::type> -{ - enum { - Transpose = StorageOrder==RowMajor - }; - typedef typename conditional::type LhsScalar; - typedef typename conditional::type RhsScalar; - typedef gebp_traits Traits; - - DenseIndex m_sizeA; - DenseIndex m_sizeB; - DenseIndex m_sizeW; - - public: - - gemm_blocking_space(DenseIndex rows, DenseIndex cols, DenseIndex depth) - { - this->m_mc = Transpose ? cols : rows; - this->m_nc = Transpose ? rows : cols; - this->m_kc = depth; - - 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; - } - - void allocateA() - { - if(this->m_blockA==0) - this->m_blockA = aligned_new(m_sizeA); - } - - void allocateB() - { - if(this->m_blockB==0) - this->m_blockB = aligned_new(m_sizeB); - } - - void allocateW() - { - if(this->m_blockW==0) - this->m_blockW = aligned_new(m_sizeW); - } - - void allocateAll() - { - allocateA(); - allocateB(); - allocateW(); - } - - ~gemm_blocking_space() - { - aligned_delete(this->m_blockA, m_sizeA); - aligned_delete(this->m_blockB, m_sizeB); - aligned_delete(this->m_blockW, m_sizeW); - } -}; - -} // end namespace internal - -template -class GeneralProduct - : public ProductBase, Lhs, Rhs> -{ - enum { - MaxDepthAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED(Lhs::MaxColsAtCompileTime,Rhs::MaxRowsAtCompileTime) - }; - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - - typedef typename Lhs::Scalar LhsScalar; - typedef typename Rhs::Scalar RhsScalar; - typedef Scalar ResScalar; - - GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - { -#if !(defined(EIGEN_NO_STATIC_ASSERT) && defined(EIGEN_NO_DEBUG)) - typedef internal::scalar_product_op BinOp; - EIGEN_CHECK_BINARY_COMPATIBILIY(BinOp,LhsScalar,RhsScalar); -#endif - } - - template void scaleAndAddTo(Dest& dst, const Scalar& alpha) const - { - eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); - if(m_lhs.cols()==0 || m_lhs.rows()==0 || m_rhs.cols()==0) - return; - - 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,LhsScalar,RhsScalar, - Dest::MaxRowsAtCompileTime,Dest::MaxColsAtCompileTime,MaxDepthAtCompileTime> BlockingType; - - typedef internal::gemm_functor< - Scalar, Index, - internal::general_matrix_matrix_product< - Index, - LhsScalar, (_ActualLhsType::Flags&RowMajorBit) ? RowMajor : ColMajor, bool(LhsBlasTraits::NeedToConjugate), - RhsScalar, (_ActualRhsType::Flags&RowMajorBit) ? RowMajor : ColMajor, bool(RhsBlasTraits::NeedToConjugate), - (Dest::Flags&RowMajorBit) ? RowMajor : ColMajor>, - _ActualLhsType, _ActualRhsType, Dest, BlockingType> GemmFunctor; - - BlockingType blocking(dst.rows(), dst.cols(), lhs.cols()); - - internal::parallelize_gemm<(Dest::MaxRowsAtCompileTime>32 || Dest::MaxRowsAtCompileTime==Dynamic)>(GemmFunctor(lhs, rhs, dst, actualAlpha, blocking), this->rows(), this->cols(), Dest::Flags&RowMajorBit); - } -}; - -} // end namespace Eigen - -#endif // EIGEN_GENERAL_MATRIX_MATRIX_H diff --git a/splinter/src/Core/util/Meta.h b/splinter/src/Core/util/Meta.h deleted file mode 100644 index 71d5871087..0000000000 --- a/splinter/src/Core/util/Meta.h +++ /dev/null @@ -1,243 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// 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 - * \file Meta.h - * This file contains generic metaprogramming classes which are not specifically related to Eigen. - * \note In case you wonder, yes we're aware that Boost already provides all these features, - * we however don't want to add a dependency to Boost. - */ - -struct true_type { enum { value = 1 }; }; -struct false_type { enum { value = 0 }; }; - -template -struct conditional { typedef Then type; }; - -template -struct conditional { typedef Else type; }; - -template struct is_same { enum { value = 0 }; }; -template struct is_same { enum { value = 1 }; }; - -template struct remove_reference { typedef T type; }; -template struct remove_reference { typedef T type; }; - -template struct remove_pointer { typedef T type; }; -template struct remove_pointer { typedef T type; }; -template struct remove_pointer { typedef T type; }; - -template struct remove_const { typedef T type; }; -template struct remove_const { typedef T type; }; -template struct remove_const { typedef T type[]; }; -template struct remove_const { typedef T type[Size]; }; - -template struct remove_all { typedef T type; }; -template struct remove_all { typedef typename remove_all::type type; }; -template struct remove_all { typedef typename remove_all::type type; }; -template struct remove_all { typedef typename remove_all::type type; }; -template struct remove_all { typedef typename remove_all::type type; }; -template struct remove_all { typedef typename remove_all::type type; }; - -template struct is_arithmetic { enum { value = false }; }; -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 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 is_arithmetic { enum { value = true }; }; - -template struct add_const { typedef const T type; }; -template struct add_const { typedef T& type; }; - -template struct is_const { enum { value = 0 }; }; -template struct is_const { enum { value = 1 }; }; - -template struct add_const_on_value_type { typedef const T type; }; -template struct add_const_on_value_type { typedef T const& type; }; -template struct add_const_on_value_type { typedef T const* type; }; -template struct add_const_on_value_type { typedef T const* const type; }; -template struct add_const_on_value_type { typedef T const* const type; }; - -/** \internal Allows to enable/disable an overload - * according to a compile time condition. - */ -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. - * - * It supports both the current STL mechanism (using the result_type member) as well as - * upcoming next STL generation (using a templated result member). - * If none of these members is provided, then the type of the first argument is returned. FIXME, that behavior is a pretty bad hack. - */ -template struct result_of {}; - -struct has_none {int a[1];}; -struct has_std_result_type {int a[2];}; -struct has_tr1_result {int a[3];}; - -template -struct unary_result_of_select {typedef ArgType type;}; - -template -struct unary_result_of_select {typedef typename Func::result_type type;}; - -template -struct unary_result_of_select {typedef typename Func::template result::type type;}; - -template -struct result_of { - template - static has_std_result_type testFunctor(T const *, typename T::result_type const * = 0); - template - static has_tr1_result testFunctor(T const *, typename T::template result::type const * = 0); - static has_none testFunctor(...); - - // note that the following indirection is needed for gcc-3.3 - enum {FunctorType = sizeof(testFunctor(static_cast(0)))}; - typedef typename unary_result_of_select::type type; -}; - -template -struct binary_result_of_select {typedef ArgType0 type;}; - -template -struct binary_result_of_select -{typedef typename Func::result_type type;}; - -template -struct binary_result_of_select -{typedef typename Func::template result::type type;}; - -template -struct result_of { - template - static has_std_result_type testFunctor(T const *, typename T::result_type const * = 0); - template - static has_tr1_result testFunctor(T const *, typename T::template result::type const * = 0); - static has_none testFunctor(...); - - // note that the following indirection is needed for gcc-3.3 - enum {FunctorType = sizeof(testFunctor(static_cast(0)))}; - typedef typename binary_result_of_select::type type; -}; - -/** \internal In short, it computes int(sqrt(\a Y)) with \a Y an integer. - * Usage example: \code meta_sqrt<1023>::ret \endcode - */ -template Y))) > - // use ?: instead of || just to shut up a stupid gcc 4.3 warning -class meta_sqrt -{ - enum { - MidX = (InfX+SupX)/2, - TakeInf = MidX*MidX > Y ? 1 : 0, - NewInf = int(TakeInf) ? InfX : int(MidX), - NewSup = int(TakeInf) ? int(MidX) : SupX - }; - public: - enum { ret = meta_sqrt::ret }; -}; - -template -class meta_sqrt { public: enum { ret = (SupX*SupX <= Y) ? SupX : InfX }; }; - -/** \internal determines whether the product of two numeric types is allowed and what the return type is */ -template struct scalar_product_traits -{ - enum { Defined = 0 }; -}; - -template struct scalar_product_traits -{ - enum { - // Cost = NumTraits::MulCost, - Defined = 1 - }; - typedef T ReturnType; -}; - -template struct scalar_product_traits > -{ - enum { - // Cost = 2*NumTraits::MulCost, - Defined = 1 - }; - typedef std::complex ReturnType; -}; - -template struct scalar_product_traits, T> -{ - enum { - // Cost = 2*NumTraits::MulCost, - Defined = 1 - }; - typedef std::complex ReturnType; -}; - -// FIXME quick workaround around current limitation of result_of -// template -// struct result_of(ArgType0,ArgType1)> { -// typedef typename scalar_product_traits::type, typename remove_all::type>::ReturnType type; -// }; - -template struct is_diagonal -{ enum { ret = false }; }; - -template struct is_diagonal > -{ enum { ret = true }; }; - -template struct is_diagonal > -{ enum { ret = true }; }; - -template struct is_diagonal > -{ enum { ret = true }; }; - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_META_H diff --git a/splinter/src/Core/util/ReenableStupidWarnings.h b/splinter/src/Core/util/ReenableStupidWarnings.h deleted file mode 100644 index 5ddfbd4aa6..0000000000 --- a/splinter/src/Core/util/ReenableStupidWarnings.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifdef EIGEN_WARNINGS_DISABLED -#undef EIGEN_WARNINGS_DISABLED - -#ifndef EIGEN_PERMANENTLY_DISABLE_STUPID_WARNINGS - #ifdef _MSC_VER - #pragma warning( pop ) - #elif defined __INTEL_COMPILER - #pragma warning pop - #elif defined __clang__ - #pragma clang diagnostic pop - #endif -#endif - -#endif // EIGEN_WARNINGS_DISABLED diff --git a/splinter/src/Core/util/XprHelper.h b/splinter/src/Core/util/XprHelper.h deleted file mode 100644 index d05f8e5f6f..0000000000 --- a/splinter/src/Core/util/XprHelper.h +++ /dev/null @@ -1,469 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// 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 - -// just a workaround because GCC seems to not really like empty structs -// FIXME: gcc 4.3 generates bad code when strict-aliasing is enabled -// so currently we simply disable this optimization for gcc 4.3 -#if (defined __GNUG__) && !((__GNUC__==4) && (__GNUC_MINOR__==3)) - #define EIGEN_EMPTY_STRUCT_CTOR(X) \ - EIGEN_STRONG_INLINE X() {} \ - EIGEN_STRONG_INLINE X(const X& ) {} -#else - #define EIGEN_EMPTY_STRUCT_CTOR(X) -#endif - -namespace Eigen { - -typedef EIGEN_DEFAULT_DENSE_INDEX_TYPE DenseIndex; - -namespace internal { - -//classes inheriting no_assignment_operator don't generate a default operator=. -class no_assignment_operator -{ - private: - no_assignment_operator& operator=(const no_assignment_operator&); -}; - -/** \internal return the index type with the largest number of bits */ -template -struct promote_index_type -{ - typedef typename conditional<(sizeof(I1)::type type; -}; - -/** \internal If the template parameter Value is Dynamic, this class is just a wrapper around a T variable that - * can be accessed using value() and setValue(). - * Otherwise, this class is an empty structure and value() just returns the template parameter Value. - */ -template class variable_if_dynamic -{ - public: - EIGEN_EMPTY_STRUCT_CTOR(variable_if_dynamic) - explicit variable_if_dynamic(T v) { EIGEN_ONLY_USED_FOR_DEBUG(v); assert(v == T(Value)); } - static T value() { return T(Value); } - void setValue(T) {} -}; - -template class variable_if_dynamic -{ - T m_value; - variable_if_dynamic() { assert(false); } - public: - explicit variable_if_dynamic(T value) : m_value(value) {} - T value() const { return m_value; } - void setValue(T value) { m_value = value; } -}; - -/** \internal like variable_if_dynamic but for DynamicIndex - */ -template class variable_if_dynamicindex -{ - public: - EIGEN_EMPTY_STRUCT_CTOR(variable_if_dynamicindex) - explicit variable_if_dynamicindex(T v) { EIGEN_ONLY_USED_FOR_DEBUG(v); assert(v == T(Value)); } - static T value() { return T(Value); } - void setValue(T) {} -}; - -template class variable_if_dynamicindex -{ - T m_value; - variable_if_dynamicindex() { assert(false); } - public: - explicit variable_if_dynamicindex(T value) : m_value(value) {} - T value() const { return m_value; } - void setValue(T value) { m_value = value; } -}; - -template struct functor_traits -{ - enum - { - Cost = 10, - PacketAccess = false, - IsRepeatable = false - }; -}; - -template struct packet_traits; - -template struct unpacket_traits -{ - typedef T type; - enum {size=1}; -}; - -template class make_proper_matrix_type -{ - enum { - IsColVector = _Cols==1 && _Rows!=1, - IsRowVector = _Rows==1 && _Cols!=1, - Options = IsColVector ? (_Options | ColMajor) & ~RowMajor - : IsRowVector ? (_Options | RowMajor) & ~ColMajor - : _Options - }; - public: - typedef Matrix<_Scalar, _Rows, _Cols, Options, _MaxRows, _MaxCols> type; -}; - -template -class compute_matrix_flags -{ - enum { - row_major_bit = Options&RowMajor ? RowMajorBit : 0, - is_dynamic_size_storage = MaxRows==Dynamic || MaxCols==Dynamic, - - aligned_bit = - ( - ((Options&DontAlign)==0) - && ( -#if EIGEN_ALIGN_STATICALLY - ((!is_dynamic_size_storage) && (((MaxCols*MaxRows*int(sizeof(Scalar))) % 16) == 0)) -#else - 0 -#endif - - || - -#if EIGEN_ALIGN - is_dynamic_size_storage -#else - 0 -#endif - - ) - ) ? AlignedBit : 0, - packet_access_bit = packet_traits::Vectorizable && aligned_bit ? PacketAccessBit : 0 - }; - - public: - enum { ret = LinearAccessBit | LvalueBit | DirectAccessBit | NestByRefBit | packet_access_bit | row_major_bit | aligned_bit }; -}; - -template struct size_at_compile_time -{ - enum { ret = (_Rows==Dynamic || _Cols==Dynamic) ? Dynamic : _Rows * _Cols }; -}; - -/* plain_matrix_type : the difference from eval is that plain_matrix_type is always a plain matrix type, - * whereas eval is a const reference in the case of a matrix - */ - -template::StorageKind> struct plain_matrix_type; -template struct plain_matrix_type_dense; -template struct plain_matrix_type -{ - typedef typename plain_matrix_type_dense::XprKind>::type type; -}; - -template struct plain_matrix_type_dense -{ - typedef Matrix::Scalar, - traits::RowsAtCompileTime, - traits::ColsAtCompileTime, - AutoAlign | (traits::Flags&RowMajorBit ? RowMajor : ColMajor), - traits::MaxRowsAtCompileTime, - traits::MaxColsAtCompileTime - > type; -}; - -template struct plain_matrix_type_dense -{ - typedef Array::Scalar, - traits::RowsAtCompileTime, - traits::ColsAtCompileTime, - AutoAlign | (traits::Flags&RowMajorBit ? RowMajor : ColMajor), - traits::MaxRowsAtCompileTime, - traits::MaxColsAtCompileTime - > type; -}; - -/* eval : the return type of eval(). For matrices, this is just a const reference - * in order to avoid a useless copy - */ - -template::StorageKind> struct eval; - -template struct eval -{ - typedef typename plain_matrix_type::type type; -// typedef typename T::PlainObject type; -// typedef T::Matrix::Scalar, -// traits::RowsAtCompileTime, -// traits::ColsAtCompileTime, -// AutoAlign | (traits::Flags&RowMajorBit ? RowMajor : ColMajor), -// traits::MaxRowsAtCompileTime, -// traits::MaxColsAtCompileTime -// > type; -}; - -// for matrices, no need to evaluate, just use a const reference to avoid a useless copy -template -struct eval, Dense> -{ - typedef const Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>& type; -}; - -template -struct eval, Dense> -{ - typedef const Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>& type; -}; - - - -/* plain_matrix_type_column_major : same as plain_matrix_type but guaranteed to be column-major - */ -template struct plain_matrix_type_column_major -{ - enum { Rows = traits::RowsAtCompileTime, - Cols = traits::ColsAtCompileTime, - MaxRows = traits::MaxRowsAtCompileTime, - MaxCols = traits::MaxColsAtCompileTime - }; - typedef Matrix::Scalar, - Rows, - Cols, - (MaxRows==1&&MaxCols!=1) ? RowMajor : ColMajor, - MaxRows, - MaxCols - > type; -}; - -/* plain_matrix_type_row_major : same as plain_matrix_type but guaranteed to be row-major - */ -template struct plain_matrix_type_row_major -{ - enum { Rows = traits::RowsAtCompileTime, - Cols = traits::ColsAtCompileTime, - MaxRows = traits::MaxRowsAtCompileTime, - MaxCols = traits::MaxColsAtCompileTime - }; - typedef Matrix::Scalar, - Rows, - Cols, - (MaxCols==1&&MaxRows!=1) ? RowMajor : ColMajor, - MaxRows, - MaxCols - > type; -}; - -// we should be able to get rid of this one too -template struct must_nest_by_value { enum { ret = false }; }; - -/** \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&, - 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; -}; - -/** \internal Determines how a given expression should be nested into another one. - * For example, when you do a * (b+c), Eigen will determine how the expression b+c should be - * nested into the bigger product expression. The choice is between nesting the expression b+c as-is, or - * evaluating that expression b+c into a temporary variable d, and nest d so that the resulting expression is - * a*d. Evaluating can be beneficial for example if every coefficient access in the resulting expression causes - * many coefficient accesses in the nested expressions -- as is the case with matrix product for example. - * - * \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 - * nested determined that in this case it was better to evaluate the expression b+c into a temporary. On the other hand, - * since a is of type Matrix3d, the Product expression nests it as nested::ret, which turns out to be - * const Matrix3d&, because the internal logic of nested determined that since a was already a matrix, there was no point - * in copying it into another matrix. - */ -template::type> struct nested -{ - enum { - // for the purpose of this test, to keep it reasonably simple, we arbitrarily choose a value of Dynamic values. - // the choice of 10000 makes it larger than any practical fixed value and even most dynamic values. - // in extreme cases where these assumptions would be wrong, we would still at worst suffer performance issues - // (poor choice of temporaries). - // it's important that this value can still be squared without integer overflowing. - DynamicAsInteger = 10000, - ScalarReadCost = NumTraits::Scalar>::ReadCost, - ScalarReadCostAsInteger = ScalarReadCost == Dynamic ? int(DynamicAsInteger) : int(ScalarReadCost), - CoeffReadCost = traits::CoeffReadCost, - CoeffReadCostAsInteger = CoeffReadCost == Dynamic ? int(DynamicAsInteger) : int(CoeffReadCost), - NAsInteger = n == Dynamic ? int(DynamicAsInteger) : n, - CostEvalAsInteger = (NAsInteger+1) * ScalarReadCostAsInteger + CoeffReadCostAsInteger, - CostNoEvalAsInteger = NAsInteger * CoeffReadCostAsInteger - }; - - typedef typename conditional< - ( (int(traits::Flags) & EvalBeforeNestingBit) || - int(CostEvalAsInteger) < int(CostNoEvalAsInteger) - ), - PlainObject, - typename ref_selector::type - >::type type; -}; - -template -inline T* const_cast_ptr(const T* ptr) -{ - return const_cast(ptr); -} - -template::XprKind> -struct dense_xpr_base -{ - /* dense_xpr_base should only ever be used on dense expressions, thus falling either into the MatrixXpr or into the ArrayXpr cases */ -}; - -template -struct dense_xpr_base -{ - typedef MatrixBase type; -}; - -template -struct dense_xpr_base -{ - typedef ArrayBase type; -}; - -/** \internal Helper base class to add a scalar multiple operator - * overloads for complex types */ -template::value > -struct special_scalar_op_base : public BaseType -{ - // dummy operator* so that the - // "using special_scalar_op_base::operator*" compiles - void operator*() const; -}; - -template -struct special_scalar_op_base : public BaseType -{ - const CwiseUnaryOp, Derived> - operator*(const OtherScalar& scalar) const - { - return CwiseUnaryOp, Derived> - (*static_cast(this), scalar_multiple2_op(scalar)); - } - - inline friend const CwiseUnaryOp, Derived> - operator*(const OtherScalar& scalar, const Derived& matrix) - { return static_cast(matrix).operator*(scalar); } -}; - -template struct cast_return_type -{ - typedef typename XprType::Scalar CurrentScalarType; - typedef typename remove_all::type _CastType; - typedef typename _CastType::Scalar NewScalarType; - typedef typename conditional::value, - const XprType&,CastType>::type type; -}; - -template struct promote_storage_type; - -template struct promote_storage_type -{ - typedef A ret; -}; - -/** \internal gives the plain matrix or array type to store a row/column/diagonal of a matrix type. - * \param Scalar optional parameter allowing to pass a different scalar type than the one of the MatrixType. - */ -template -struct plain_row_type -{ - typedef Matrix MatrixRowType; - typedef Array ArrayRowType; - - typedef typename conditional< - is_same< typename traits::XprKind, MatrixXpr >::value, - MatrixRowType, - ArrayRowType - >::type type; -}; - -template -struct plain_col_type -{ - typedef Matrix MatrixColType; - typedef Array ArrayColType; - - typedef typename conditional< - is_same< typename traits::XprKind, MatrixXpr >::value, - MatrixColType, - ArrayColType - >::type type; -}; - -template -struct plain_diag_type -{ - enum { diag_size = EIGEN_SIZE_MIN_PREFER_DYNAMIC(ExpressionType::RowsAtCompileTime, ExpressionType::ColsAtCompileTime), - max_diag_size = EIGEN_SIZE_MIN_PREFER_FIXED(ExpressionType::MaxRowsAtCompileTime, ExpressionType::MaxColsAtCompileTime) - }; - typedef Matrix MatrixDiagType; - typedef Array ArrayDiagType; - - typedef typename conditional< - is_same< typename traits::XprKind, MatrixXpr >::value, - MatrixDiagType, - ArrayDiagType - >::type type; -}; - -template -struct is_lvalue -{ - enum { value = !bool(is_const::value) && - bool(traits::Flags & LvalueBit) }; -}; - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_XPRHELPER_H diff --git a/splinter/src/Eigen2Support/Block.h b/splinter/src/Eigen2Support/Block.h deleted file mode 100644 index 604456f40e..0000000000 --- a/splinter/src/Eigen2Support/Block.h +++ /dev/null @@ -1,126 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// 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, - * \a Eigen::BottomLeft, \a Eigen::BottomRight. - * \param cRows the number of rows in the corner - * \param cCols the number of columns in the corner - * - * Example: \include MatrixBase_corner_enum_int_int.cpp - * Output: \verbinclude MatrixBase_corner_enum_int_int.out - * - * \note Even though the returned expression has dynamic size, in the case - * when it is applied to a fixed-size matrix, it inherits a fixed maximal size, - * which means that evaluating it does not cause a dynamic memory allocation. - * - * \sa class Block, block(Index,Index,Index,Index) - */ -template -inline Block DenseBase - ::corner(CornerType type, Index cRows, Index cCols) -{ - switch(type) - { - default: - eigen_assert(false && "Bad corner type."); - case TopLeft: - return Block(derived(), 0, 0, cRows, cCols); - case TopRight: - return Block(derived(), 0, cols() - cCols, cRows, cCols); - case BottomLeft: - return Block(derived(), rows() - cRows, 0, cRows, cCols); - case BottomRight: - return Block(derived(), rows() - cRows, cols() - cCols, cRows, cCols); - } -} - -/** This is the const version of corner(CornerType, Index, Index).*/ -template -inline const Block -DenseBase::corner(CornerType type, Index cRows, Index cCols) const -{ - switch(type) - { - default: - eigen_assert(false && "Bad corner type."); - case TopLeft: - return Block(derived(), 0, 0, cRows, cCols); - case TopRight: - return Block(derived(), 0, cols() - cCols, cRows, cCols); - case BottomLeft: - return Block(derived(), rows() - cRows, 0, cRows, cCols); - case BottomRight: - return Block(derived(), rows() - cRows, cols() - cCols, cRows, cCols); - } -} - -/** \returns a fixed-size expression of a corner of *this. - * - * \param type the type of corner. Can be \a Eigen::TopLeft, \a Eigen::TopRight, - * \a Eigen::BottomLeft, \a Eigen::BottomRight. - * - * The template parameters CRows and CCols arethe number of rows and columns in the corner. - * - * Example: \include MatrixBase_template_int_int_corner_enum.cpp - * Output: \verbinclude MatrixBase_template_int_int_corner_enum.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -template -template -inline Block -DenseBase::corner(CornerType type) -{ - switch(type) - { - default: - eigen_assert(false && "Bad corner type."); - case TopLeft: - return Block(derived(), 0, 0); - case TopRight: - return Block(derived(), 0, cols() - CCols); - case BottomLeft: - return Block(derived(), rows() - CRows, 0); - case BottomRight: - return Block(derived(), rows() - CRows, cols() - CCols); - } -} - -/** This is the const version of corner(CornerType).*/ -template -template -inline const Block -DenseBase::corner(CornerType type) const -{ - switch(type) - { - default: - eigen_assert(false && "Bad corner type."); - case TopLeft: - return Block(derived(), 0, 0); - case TopRight: - return Block(derived(), 0, cols() - CCols); - case BottomLeft: - return Block(derived(), rows() - CRows, 0); - case BottomRight: - return Block(derived(), rows() - CRows, cols() - CCols); - } -} - -} // end namespace Eigen - -#endif // EIGEN_BLOCK2_H diff --git a/splinter/src/Eigen2Support/Cwise.h b/splinter/src/Eigen2Support/Cwise.h deleted file mode 100644 index d95009b6e2..0000000000 --- a/splinter/src/Eigen2Support/Cwise.h +++ /dev/null @@ -1,192 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2008 Benoit Jacob -// -// 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) \ - CwiseBinaryOp::Scalar>, ExpressionType, OtherDerived> - -/** \internal - * convenient macro to defined the return type of a cwise unary operation */ -#define EIGEN_CWISE_UNOP_RETURN_TYPE(OP) \ - CwiseUnaryOp::Scalar>, ExpressionType> - -/** \internal - * convenient macro to defined the return type of a cwise comparison to a scalar */ -#define EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(OP) \ - CwiseBinaryOp::Scalar>, ExpressionType, \ - typename ExpressionType::ConstantReturnType > - -/** \class Cwise - * - * \brief Pseudo expression providing additional coefficient-wise operations - * - * \param ExpressionType the type of the object on which to do coefficient-wise operations - * - * This class represents an expression with additional coefficient-wise features. - * It is the return type of MatrixBase::cwise() - * and most of the time this is the only way it is used. - * - * Example: \include MatrixBase_cwise_const.cpp - * Output: \verbinclude MatrixBase_cwise_const.out - * - * 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_CWISE_PLUGIN. - * - * \sa MatrixBase::cwise() const, MatrixBase::cwise() - */ -template class Cwise -{ - public: - - typedef typename internal::traits::Scalar Scalar; - typedef typename internal::conditional::ret, - ExpressionType, const ExpressionType&>::type ExpressionTypeNested; - typedef CwiseUnaryOp, ExpressionType> ScalarAddReturnType; - - inline Cwise(const ExpressionType& matrix) : m_matrix(matrix) {} - - /** \internal */ - inline const ExpressionType& _expression() const { return m_matrix; } - - template - const EIGEN_CWISE_PRODUCT_RETURN_TYPE(ExpressionType,OtherDerived) - operator*(const MatrixBase &other) const; - - template - const EIGEN_CWISE_BINOP_RETURN_TYPE(internal::scalar_quotient_op) - operator/(const MatrixBase &other) const; - - /** \deprecated ArrayBase::min() */ - template - const EIGEN_CWISE_BINOP_RETURN_TYPE(internal::scalar_min_op) - (min)(const MatrixBase &other) const - { return EIGEN_CWISE_BINOP_RETURN_TYPE(internal::scalar_min_op)(_expression(), other.derived()); } - - /** \deprecated ArrayBase::max() */ - template - const EIGEN_CWISE_BINOP_RETURN_TYPE(internal::scalar_max_op) - (max)(const MatrixBase &other) const - { return EIGEN_CWISE_BINOP_RETURN_TYPE(internal::scalar_max_op)(_expression(), other.derived()); } - - const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_abs_op) abs() const; - const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_abs2_op) abs2() const; - const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_square_op) square() const; - const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_cube_op) cube() const; - const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_inverse_op) inverse() const; - const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_sqrt_op) sqrt() const; - const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_exp_op) exp() const; - const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_log_op) log() const; - const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_cos_op) cos() const; - const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_sin_op) sin() const; - const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_pow_op) pow(const Scalar& exponent) const; - - const ScalarAddReturnType - operator+(const Scalar& scalar) const; - - /** \relates Cwise */ - friend const ScalarAddReturnType - operator+(const Scalar& scalar, const Cwise& mat) - { return mat + scalar; } - - ExpressionType& operator+=(const Scalar& scalar); - - const ScalarAddReturnType - operator-(const Scalar& scalar) const; - - ExpressionType& operator-=(const Scalar& scalar); - - template - inline ExpressionType& operator*=(const MatrixBase &other); - - template - inline ExpressionType& operator/=(const MatrixBase &other); - - template const EIGEN_CWISE_BINOP_RETURN_TYPE(std::less) - operator<(const MatrixBase& other) const; - - template const EIGEN_CWISE_BINOP_RETURN_TYPE(std::less_equal) - operator<=(const MatrixBase& other) const; - - template const EIGEN_CWISE_BINOP_RETURN_TYPE(std::greater) - operator>(const MatrixBase& other) const; - - template const EIGEN_CWISE_BINOP_RETURN_TYPE(std::greater_equal) - operator>=(const MatrixBase& other) const; - - template const EIGEN_CWISE_BINOP_RETURN_TYPE(std::equal_to) - operator==(const MatrixBase& other) const; - - template const EIGEN_CWISE_BINOP_RETURN_TYPE(std::not_equal_to) - operator!=(const MatrixBase& other) const; - - // comparisons to a scalar value - const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::less) - operator<(Scalar s) const; - - const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::less_equal) - operator<=(Scalar s) const; - - const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::greater) - operator>(Scalar s) const; - - const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::greater_equal) - operator>=(Scalar s) const; - - const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::equal_to) - operator==(Scalar s) const; - - const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::not_equal_to) - operator!=(Scalar s) const; - - // allow to extend Cwise outside Eigen - #ifdef EIGEN_CWISE_PLUGIN - #include EIGEN_CWISE_PLUGIN - #endif - - protected: - ExpressionTypeNested m_matrix; -}; - - -/** \returns a Cwise wrapper of *this providing additional coefficient-wise operations - * - * Example: \include MatrixBase_cwise_const.cpp - * Output: \verbinclude MatrixBase_cwise_const.out - * - * \sa class Cwise, cwise() - */ -template -inline const Cwise MatrixBase::cwise() const -{ - return derived(); -} - -/** \returns a Cwise wrapper of *this providing additional coefficient-wise operations - * - * Example: \include MatrixBase_cwise.cpp - * Output: \verbinclude MatrixBase_cwise.out - * - * \sa class Cwise, cwise() const - */ -template -inline Cwise MatrixBase::cwise() -{ - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_CWISE_H diff --git a/splinter/src/Eigen2Support/CwiseOperators.h b/splinter/src/Eigen2Support/CwiseOperators.h deleted file mode 100644 index 482f306485..0000000000 --- a/splinter/src/Eigen2Support/CwiseOperators.h +++ /dev/null @@ -1,298 +0,0 @@ -// 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_ARRAY_CWISE_OPERATORS_H -#define EIGEN_ARRAY_CWISE_OPERATORS_H - -namespace Eigen { - -/*************************************************************************** -* The following functions were defined in Core -***************************************************************************/ - - -/** \deprecated ArrayBase::abs() */ -template -EIGEN_STRONG_INLINE const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_abs_op) -Cwise::abs() const -{ - return _expression(); -} - -/** \deprecated ArrayBase::abs2() */ -template -EIGEN_STRONG_INLINE const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_abs2_op) -Cwise::abs2() const -{ - return _expression(); -} - -/** \deprecated ArrayBase::exp() */ -template -inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_exp_op) -Cwise::exp() const -{ - return _expression(); -} - -/** \deprecated ArrayBase::log() */ -template -inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_log_op) -Cwise::log() const -{ - return _expression(); -} - -/** \deprecated ArrayBase::operator*() */ -template -template -EIGEN_STRONG_INLINE const EIGEN_CWISE_PRODUCT_RETURN_TYPE(ExpressionType,OtherDerived) -Cwise::operator*(const MatrixBase &other) const -{ - return EIGEN_CWISE_PRODUCT_RETURN_TYPE(ExpressionType,OtherDerived)(_expression(), other.derived()); -} - -/** \deprecated ArrayBase::operator/() */ -template -template -EIGEN_STRONG_INLINE const EIGEN_CWISE_BINOP_RETURN_TYPE(internal::scalar_quotient_op) -Cwise::operator/(const MatrixBase &other) const -{ - return EIGEN_CWISE_BINOP_RETURN_TYPE(internal::scalar_quotient_op)(_expression(), other.derived()); -} - -/** \deprecated ArrayBase::operator*=() */ -template -template -inline ExpressionType& Cwise::operator*=(const MatrixBase &other) -{ - return m_matrix.const_cast_derived() = *this * other; -} - -/** \deprecated ArrayBase::operator/=() */ -template -template -inline ExpressionType& Cwise::operator/=(const MatrixBase &other) -{ - return m_matrix.const_cast_derived() = *this / other; -} - -/*************************************************************************** -* The following functions were defined in Array -***************************************************************************/ - -// -- unary operators -- - -/** \deprecated ArrayBase::sqrt() */ -template -inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_sqrt_op) -Cwise::sqrt() const -{ - return _expression(); -} - -/** \deprecated ArrayBase::cos() */ -template -inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_cos_op) -Cwise::cos() const -{ - return _expression(); -} - - -/** \deprecated ArrayBase::sin() */ -template -inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_sin_op) -Cwise::sin() const -{ - return _expression(); -} - - -/** \deprecated ArrayBase::log() */ -template -inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_pow_op) -Cwise::pow(const Scalar& exponent) const -{ - return EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_pow_op)(_expression(), internal::scalar_pow_op(exponent)); -} - - -/** \deprecated ArrayBase::inverse() */ -template -inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_inverse_op) -Cwise::inverse() const -{ - return _expression(); -} - -/** \deprecated ArrayBase::square() */ -template -inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_square_op) -Cwise::square() const -{ - return _expression(); -} - -/** \deprecated ArrayBase::cube() */ -template -inline const EIGEN_CWISE_UNOP_RETURN_TYPE(internal::scalar_cube_op) -Cwise::cube() const -{ - return _expression(); -} - - -// -- binary operators -- - -/** \deprecated ArrayBase::operator<() */ -template -template -inline const EIGEN_CWISE_BINOP_RETURN_TYPE(std::less) -Cwise::operator<(const MatrixBase &other) const -{ - return EIGEN_CWISE_BINOP_RETURN_TYPE(std::less)(_expression(), other.derived()); -} - -/** \deprecated ArrayBase::<=() */ -template -template -inline const EIGEN_CWISE_BINOP_RETURN_TYPE(std::less_equal) -Cwise::operator<=(const MatrixBase &other) const -{ - return EIGEN_CWISE_BINOP_RETURN_TYPE(std::less_equal)(_expression(), other.derived()); -} - -/** \deprecated ArrayBase::operator>() */ -template -template -inline const EIGEN_CWISE_BINOP_RETURN_TYPE(std::greater) -Cwise::operator>(const MatrixBase &other) const -{ - return EIGEN_CWISE_BINOP_RETURN_TYPE(std::greater)(_expression(), other.derived()); -} - -/** \deprecated ArrayBase::operator>=() */ -template -template -inline const EIGEN_CWISE_BINOP_RETURN_TYPE(std::greater_equal) -Cwise::operator>=(const MatrixBase &other) const -{ - return EIGEN_CWISE_BINOP_RETURN_TYPE(std::greater_equal)(_expression(), other.derived()); -} - -/** \deprecated ArrayBase::operator==() */ -template -template -inline const EIGEN_CWISE_BINOP_RETURN_TYPE(std::equal_to) -Cwise::operator==(const MatrixBase &other) const -{ - return EIGEN_CWISE_BINOP_RETURN_TYPE(std::equal_to)(_expression(), other.derived()); -} - -/** \deprecated ArrayBase::operator!=() */ -template -template -inline const EIGEN_CWISE_BINOP_RETURN_TYPE(std::not_equal_to) -Cwise::operator!=(const MatrixBase &other) const -{ - return EIGEN_CWISE_BINOP_RETURN_TYPE(std::not_equal_to)(_expression(), other.derived()); -} - -// comparisons to scalar value - -/** \deprecated ArrayBase::operator<(Scalar) */ -template -inline const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::less) -Cwise::operator<(Scalar s) const -{ - return EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::less)(_expression(), - typename ExpressionType::ConstantReturnType(_expression().rows(), _expression().cols(), s)); -} - -/** \deprecated ArrayBase::operator<=(Scalar) */ -template -inline const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::less_equal) -Cwise::operator<=(Scalar s) const -{ - return EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::less_equal)(_expression(), - typename ExpressionType::ConstantReturnType(_expression().rows(), _expression().cols(), s)); -} - -/** \deprecated ArrayBase::operator>(Scalar) */ -template -inline const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::greater) -Cwise::operator>(Scalar s) const -{ - return EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::greater)(_expression(), - typename ExpressionType::ConstantReturnType(_expression().rows(), _expression().cols(), s)); -} - -/** \deprecated ArrayBase::operator>=(Scalar) */ -template -inline const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::greater_equal) -Cwise::operator>=(Scalar s) const -{ - return EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::greater_equal)(_expression(), - typename ExpressionType::ConstantReturnType(_expression().rows(), _expression().cols(), s)); -} - -/** \deprecated ArrayBase::operator==(Scalar) */ -template -inline const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::equal_to) -Cwise::operator==(Scalar s) const -{ - return EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::equal_to)(_expression(), - typename ExpressionType::ConstantReturnType(_expression().rows(), _expression().cols(), s)); -} - -/** \deprecated ArrayBase::operator!=(Scalar) */ -template -inline const EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::not_equal_to) -Cwise::operator!=(Scalar s) const -{ - return EIGEN_CWISE_COMP_TO_SCALAR_RETURN_TYPE(std::not_equal_to)(_expression(), - typename ExpressionType::ConstantReturnType(_expression().rows(), _expression().cols(), s)); -} - -// scalar addition - -/** \deprecated ArrayBase::operator+(Scalar) */ -template -inline const typename Cwise::ScalarAddReturnType -Cwise::operator+(const Scalar& scalar) const -{ - return typename Cwise::ScalarAddReturnType(m_matrix, internal::scalar_add_op(scalar)); -} - -/** \deprecated ArrayBase::operator+=(Scalar) */ -template -inline ExpressionType& Cwise::operator+=(const Scalar& scalar) -{ - return m_matrix.const_cast_derived() = *this + scalar; -} - -/** \deprecated ArrayBase::operator-(Scalar) */ -template -inline const typename Cwise::ScalarAddReturnType -Cwise::operator-(const Scalar& scalar) const -{ - return *this + (-scalar); -} - -/** \deprecated ArrayBase::operator-=(Scalar) */ -template -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/splinter/src/Eigen2Support/Geometry/AlignedBox.h b/splinter/src/Eigen2Support/Geometry/AlignedBox.h deleted file mode 100644 index 2e4309dd94..0000000000 --- a/splinter/src/Eigen2Support/Geometry/AlignedBox.h +++ /dev/null @@ -1,159 +0,0 @@ -// 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/. - -// 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 - * - * \class AlignedBox - * - * \brief An axis aligned box - * - * \param _Scalar the type of the scalar coefficients - * \param _AmbientDim the dimension of the ambient space, can be a compile time value or Dynamic. - * - * This class represents an axis aligned box as a pair of the minimal and maximal corners. - */ -template -class AlignedBox -{ -public: -EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim==Dynamic ? Dynamic : _AmbientDim+1) - enum { AmbientDimAtCompileTime = _AmbientDim }; - typedef _Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix VectorType; - - /** Default constructor initializing a null box. */ - inline AlignedBox() - { if (AmbientDimAtCompileTime!=Dynamic) setNull(); } - - /** Constructs a null box with \a _dim the dimension of the ambient space. */ - inline explicit AlignedBox(int _dim) : m_min(_dim), m_max(_dim) - { setNull(); } - - /** Constructs a box with extremities \a _min and \a _max. */ - inline AlignedBox(const VectorType& _min, const VectorType& _max) : m_min(_min), m_max(_max) {} - - /** Constructs a box containing a single point \a p. */ - inline explicit AlignedBox(const VectorType& p) : m_min(p), m_max(p) {} - - ~AlignedBox() {} - - /** \returns the dimension in which the box holds */ - 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(); } - - /** Makes \c *this a null/empty box. */ - inline void setNull() - { - m_min.setConstant( (std::numeric_limits::max)()); - m_max.setConstant(-(std::numeric_limits::max)()); - } - - /** \returns the minimal corner */ - inline const VectorType& (min)() const { return m_min; } - /** \returns a non const reference to the minimal corner */ - inline VectorType& (min)() { return m_min; } - /** \returns the maximal corner */ - inline const VectorType& (max)() const { return m_max; } - /** \returns a non const reference to the maximal corner */ - inline VectorType& (max)() { return m_max; } - - /** \returns true if the point \a p is inside the box \c *this. */ - inline bool contains(const VectorType& p) const - { return (m_min.cwise()<=p).all() && (p.cwise()<=m_max).all(); } - - /** \returns true if the box \a b is entirely inside the box \c *this. */ - inline bool contains(const AlignedBox& b) const - { return (m_min.cwise()<=(b.min)()).all() && ((b.max)().cwise()<=m_max).all(); } - - /** Extends \c *this such that it contains the point \a p and returns a reference to \c *this. */ - inline AlignedBox& extend(const VectorType& p) - { m_min = (m_min.cwise().min)(p); m_max = (m_max.cwise().max)(p); return *this; } - - /** Extends \c *this such that it contains the box \a b and returns a reference to \c *this. */ - inline AlignedBox& extend(const AlignedBox& b) - { m_min = (m_min.cwise().min)(b.m_min); m_max = (m_max.cwise().max)(b.m_max); return *this; } - - /** Clamps \c *this by the box \a b and returns a reference to \c *this. */ - inline AlignedBox& clamp(const AlignedBox& b) - { m_min = (m_min.cwise().max)(b.m_min); m_max = (m_max.cwise().min)(b.m_max); return *this; } - - /** Translate \c *this by the vector \a t and returns a reference to \c *this. */ - inline AlignedBox& translate(const VectorType& t) - { m_min += t; m_max += t; return *this; } - - /** \returns the squared distance between the point \a p and the box \c *this, - * and zero if \a p is inside the box. - * \sa exteriorDistance() - */ - inline Scalar squaredExteriorDistance(const VectorType& p) const; - - /** \returns the distance between the point \a p and the box \c *this, - * and zero if \a p is inside the box. - * \sa squaredExteriorDistance() - */ - inline Scalar exteriorDistance(const VectorType& p) const - { return ei_sqrt(squaredExteriorDistance(p)); } - - /** \returns \c *this with scalar type casted to \a NewScalarType - * - * Note that if \a NewScalarType is equal to the current scalar type of \c *this - * then this function smartly returns a const reference to \c *this. - */ - template - inline typename internal::cast_return_type >::type cast() const - { - return typename internal::cast_return_type >::type(*this); - } - - /** Copy constructor with scalar type conversion */ - template - inline explicit AlignedBox(const AlignedBox& other) - { - m_min = (other.min)().template cast(); - m_max = (other.max)().template cast(); - } - - /** \returns \c true if \c *this is approximately equal to \a other, within the precision - * determined by \a prec. - * - * \sa MatrixBase::isApprox() */ - bool isApprox(const AlignedBox& other, typename NumTraits::Real prec = precision()) const - { return m_min.isApprox(other.m_min, prec) && m_max.isApprox(other.m_max, prec); } - -protected: - - VectorType m_min, m_max; -}; - -template -inline Scalar AlignedBox::squaredExteriorDistance(const VectorType& p) const -{ - Scalar dist2(0); - Scalar aux; - for (int k=0; k - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#if EIGEN2_SUPPORT_STAGE < STAGE20_RESOLVE_API_CONFLICTS -#include "RotationBase.h" -#include "Rotation2D.h" -#include "Quaternion.h" -#include "AngleAxis.h" -#include "Transform.h" -#include "Translation.h" -#include "Scaling.h" -#include "AlignedBox.h" -#include "Hyperplane.h" -#include "ParametrizedLine.h" -#endif - - -#define RotationBase eigen2_RotationBase -#define Rotation2D eigen2_Rotation2D -#define Rotation2Df eigen2_Rotation2Df -#define Rotation2Dd eigen2_Rotation2Dd - -#define Quaternion eigen2_Quaternion -#define Quaternionf eigen2_Quaternionf -#define Quaterniond eigen2_Quaterniond - -#define AngleAxis eigen2_AngleAxis -#define AngleAxisf eigen2_AngleAxisf -#define AngleAxisd eigen2_AngleAxisd - -#define Transform eigen2_Transform -#define Transform2f eigen2_Transform2f -#define Transform2d eigen2_Transform2d -#define Transform3f eigen2_Transform3f -#define Transform3d eigen2_Transform3d - -#define Translation eigen2_Translation -#define Translation2f eigen2_Translation2f -#define Translation2d eigen2_Translation2d -#define Translation3f eigen2_Translation3f -#define Translation3d eigen2_Translation3d - -#define Scaling eigen2_Scaling -#define Scaling2f eigen2_Scaling2f -#define Scaling2d eigen2_Scaling2d -#define Scaling3f eigen2_Scaling3f -#define Scaling3d eigen2_Scaling3d - -#define AlignedBox eigen2_AlignedBox - -#define Hyperplane eigen2_Hyperplane -#define ParametrizedLine eigen2_ParametrizedLine - -#define ei_toRotationMatrix eigen2_ei_toRotationMatrix -#define ei_quaternion_assign_impl eigen2_ei_quaternion_assign_impl -#define ei_transform_product_impl eigen2_ei_transform_product_impl - -#include "RotationBase.h" -#include "Rotation2D.h" -#include "Quaternion.h" -#include "AngleAxis.h" -#include "Transform.h" -#include "Translation.h" -#include "Scaling.h" -#include "AlignedBox.h" -#include "Hyperplane.h" -#include "ParametrizedLine.h" - -#undef ei_toRotationMatrix -#undef ei_quaternion_assign_impl -#undef ei_transform_product_impl - -#undef RotationBase -#undef Rotation2D -#undef Rotation2Df -#undef Rotation2Dd - -#undef Quaternion -#undef Quaternionf -#undef Quaterniond - -#undef AngleAxis -#undef AngleAxisf -#undef AngleAxisd - -#undef Transform -#undef Transform2f -#undef Transform2d -#undef Transform3f -#undef Transform3d - -#undef Translation -#undef Translation2f -#undef Translation2d -#undef Translation3f -#undef Translation3d - -#undef Scaling -#undef Scaling2f -#undef Scaling2d -#undef Scaling3f -#undef Scaling3d - -#undef AlignedBox - -#undef Hyperplane -#undef ParametrizedLine - -#endif // EIGEN2_GEOMETRY_MODULE_H diff --git a/splinter/src/Eigen2Support/Geometry/AngleAxis.h b/splinter/src/Eigen2Support/Geometry/AngleAxis.h deleted file mode 100644 index af598a4031..0000000000 --- a/splinter/src/Eigen2Support/Geometry/AngleAxis.h +++ /dev/null @@ -1,214 +0,0 @@ -// 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/. - -// 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 AngleAxis - * - * \brief Represents a 3D rotation as a rotation angle around an arbitrary 3D axis - * - * \param _Scalar the scalar type, i.e., the type of the coefficients. - * - * The following two typedefs are provided for convenience: - * \li \c AngleAxisf for \c float - * \li \c AngleAxisd for \c double - * - * \addexample AngleAxisForEuler \label How to define a rotation from Euler-angles - * - * Combined with MatrixBase::Unit{X,Y,Z}, AngleAxis can be used to easily - * mimic Euler-angles. Here is an example: - * \include AngleAxis_mimic_euler.cpp - * Output: \verbinclude AngleAxis_mimic_euler.out - * - * \note This class is not aimed to be used to store a rotation transformation, - * but rather to make easier the creation of other rotation (Quaternion, rotation Matrix) - * and transformation objects. - * - * \sa class Quaternion, class Transform, MatrixBase::UnitX() - */ - -template struct ei_traits > -{ - typedef _Scalar Scalar; -}; - -template -class AngleAxis : public RotationBase,3> -{ - typedef RotationBase,3> Base; - -public: - - using Base::operator*; - - enum { Dim = 3 }; - /** the scalar type of the coefficients */ - typedef _Scalar Scalar; - typedef Matrix Matrix3; - typedef Matrix Vector3; - typedef Quaternion QuaternionType; - -protected: - - Vector3 m_axis; - Scalar m_angle; - -public: - - /** Default constructor without initialization. */ - AngleAxis() {} - /** Constructs and initialize the angle-axis rotation from an \a angle in radian - * and an \a axis which must be normalized. */ - template - inline AngleAxis(Scalar angle, const MatrixBase& axis) : m_axis(axis), m_angle(angle) {} - /** Constructs and initialize the angle-axis rotation from a quaternion \a q. */ - inline AngleAxis(const QuaternionType& q) { *this = q; } - /** Constructs and initialize the angle-axis rotation from a 3x3 rotation matrix. */ - template - inline explicit AngleAxis(const MatrixBase& m) { *this = m; } - - Scalar angle() const { return m_angle; } - Scalar& angle() { return m_angle; } - - const Vector3& axis() const { return m_axis; } - Vector3& axis() { return m_axis; } - - /** Concatenates two rotations */ - inline QuaternionType operator* (const AngleAxis& other) const - { return QuaternionType(*this) * QuaternionType(other); } - - /** Concatenates two rotations */ - inline QuaternionType operator* (const QuaternionType& other) const - { return QuaternionType(*this) * other; } - - /** Concatenates two rotations */ - friend inline QuaternionType operator* (const QuaternionType& a, const AngleAxis& b) - { return a * QuaternionType(b); } - - /** Concatenates two rotations */ - inline Matrix3 operator* (const Matrix3& other) const - { return toRotationMatrix() * other; } - - /** Concatenates two rotations */ - inline friend Matrix3 operator* (const Matrix3& a, const AngleAxis& b) - { return a * b.toRotationMatrix(); } - - /** Applies rotation to vector */ - inline Vector3 operator* (const Vector3& other) const - { return toRotationMatrix() * other; } - - /** \returns the inverse rotation, i.e., an angle-axis with opposite rotation angle */ - AngleAxis inverse() const - { return AngleAxis(-m_angle, m_axis); } - - AngleAxis& operator=(const QuaternionType& q); - template - AngleAxis& operator=(const MatrixBase& m); - - template - AngleAxis& fromRotationMatrix(const MatrixBase& m); - Matrix3 toRotationMatrix(void) const; - - /** \returns \c *this with scalar type casted to \a NewScalarType - * - * Note that if \a NewScalarType is equal to the current scalar type of \c *this - * then this function smartly returns a const reference to \c *this. - */ - template - inline typename internal::cast_return_type >::type cast() const - { return typename internal::cast_return_type >::type(*this); } - - /** Copy constructor with scalar type conversion */ - template - inline explicit AngleAxis(const AngleAxis& other) - { - m_axis = other.axis().template cast(); - m_angle = Scalar(other.angle()); - } - - /** \returns \c true if \c *this is approximately equal to \a other, within the precision - * determined by \a prec. - * - * \sa MatrixBase::isApprox() */ - bool isApprox(const AngleAxis& other, typename NumTraits::Real prec = precision()) const - { return m_axis.isApprox(other.m_axis, prec) && ei_isApprox(m_angle,other.m_angle, prec); } -}; - -/** \ingroup Geometry_Module - * single precision angle-axis type */ -typedef AngleAxis AngleAxisf; -/** \ingroup Geometry_Module - * double precision angle-axis type */ -typedef AngleAxis AngleAxisd; - -/** Set \c *this from a quaternion. - * The axis is normalized. - */ -template -AngleAxis& AngleAxis::operator=(const QuaternionType& q) -{ - Scalar n2 = q.vec().squaredNorm(); - if (n2 < precision()*precision()) - { - m_angle = 0; - m_axis << 1, 0, 0; - } - else - { - m_angle = 2*std::acos(q.w()); - m_axis = q.vec() / ei_sqrt(n2); - } - return *this; -} - -/** Set \c *this from a 3x3 rotation matrix \a mat. - */ -template -template -AngleAxis& AngleAxis::operator=(const MatrixBase& mat) -{ - // Since a direct conversion would not be really faster, - // let's use the robust Quaternion implementation: - return *this = QuaternionType(mat); -} - -/** Constructs and \returns an equivalent 3x3 rotation matrix. - */ -template -typename AngleAxis::Matrix3 -AngleAxis::toRotationMatrix(void) const -{ - Matrix3 res; - Vector3 sin_axis = ei_sin(m_angle) * m_axis; - Scalar c = ei_cos(m_angle); - Vector3 cos1_axis = (Scalar(1)-c) * m_axis; - - Scalar tmp; - tmp = cos1_axis.x() * m_axis.y(); - res.coeffRef(0,1) = tmp - sin_axis.z(); - res.coeffRef(1,0) = tmp + sin_axis.z(); - - tmp = cos1_axis.x() * m_axis.z(); - res.coeffRef(0,2) = tmp + sin_axis.y(); - res.coeffRef(2,0) = tmp - sin_axis.y(); - - tmp = cos1_axis.y() * m_axis.z(); - res.coeffRef(1,2) = tmp - sin_axis.x(); - res.coeffRef(2,1) = tmp + sin_axis.x(); - - res.diagonal() = (cos1_axis.cwise() * m_axis).cwise() + c; - - return res; -} - -} // end namespace Eigen diff --git a/splinter/src/Eigen2Support/Geometry/Hyperplane.h b/splinter/src/Eigen2Support/Geometry/Hyperplane.h deleted file mode 100644 index b95bf00ecf..0000000000 --- a/splinter/src/Eigen2Support/Geometry/Hyperplane.h +++ /dev/null @@ -1,254 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2008 Benoit Jacob -// -// 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 - * - * \brief A hyperplane - * - * A hyperplane is an affine subspace of dimension n-1 in a space of dimension n. - * For example, a hyperplane in a plane is a line; a hyperplane in 3-space is a plane. - * - * \param _Scalar the scalar type, i.e., the type of the coefficients - * \param _AmbientDim the dimension of the ambient space, can be a compile time value or Dynamic. - * Notice that the dimension of the hyperplane is _AmbientDim-1. - * - * This class represents an hyperplane as the zero set of the implicit equation - * \f$ n \cdot x + d = 0 \f$ where \f$ n \f$ is a unit normal vector of the plane (linear part) - * and \f$ d \f$ is the distance (offset) to the origin. - */ -template -class Hyperplane -{ -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim==Dynamic ? Dynamic : _AmbientDim+1) - enum { AmbientDimAtCompileTime = _AmbientDim }; - typedef _Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix VectorType; - typedef Matrix Coefficients; - typedef Block NormalReturnType; - - /** Default constructor without initialization */ - inline Hyperplane() {} - - /** Constructs a dynamic-size hyperplane with \a _dim the dimension - * of the ambient space */ - inline explicit Hyperplane(int _dim) : m_coeffs(_dim+1) {} - - /** Construct a plane from its normal \a n and a point \a e onto the plane. - * \warning the vector normal is assumed to be normalized. - */ - inline Hyperplane(const VectorType& n, const VectorType& e) - : m_coeffs(n.size()+1) - { - normal() = n; - offset() = -e.eigen2_dot(n); - } - - /** Constructs a plane from its normal \a n and distance to the origin \a d - * such that the algebraic equation of the plane is \f$ n \cdot x + d = 0 \f$. - * \warning the vector normal is assumed to be normalized. - */ - inline Hyperplane(const VectorType& n, Scalar d) - : m_coeffs(n.size()+1) - { - normal() = n; - offset() = d; - } - - /** Constructs a hyperplane passing through the two points. If the dimension of the ambient space - * is greater than 2, then there isn't uniqueness, so an arbitrary choice is made. - */ - static inline Hyperplane Through(const VectorType& p0, const VectorType& p1) - { - Hyperplane result(p0.size()); - result.normal() = (p1 - p0).unitOrthogonal(); - result.offset() = -result.normal().eigen2_dot(p0); - return result; - } - - /** Constructs a hyperplane passing through the three points. The dimension of the ambient space - * is required to be exactly 3. - */ - static inline Hyperplane Through(const VectorType& p0, const VectorType& p1, const VectorType& p2) - { - EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VectorType, 3) - Hyperplane result(p0.size()); - result.normal() = (p2 - p0).cross(p1 - p0).normalized(); - result.offset() = -result.normal().eigen2_dot(p0); - return result; - } - - /** Constructs a hyperplane passing through the parametrized line \a parametrized. - * If the dimension of the ambient space is greater than 2, then there isn't uniqueness, - * so an arbitrary choice is made. - */ - // FIXME to be consitent with the rest this could be implemented as a static Through function ?? - explicit Hyperplane(const ParametrizedLine& parametrized) - { - normal() = parametrized.direction().unitOrthogonal(); - offset() = -normal().eigen2_dot(parametrized.origin()); - } - - ~Hyperplane() {} - - /** \returns the dimension in which the plane holds */ - inline int dim() const { return int(AmbientDimAtCompileTime)==Dynamic ? m_coeffs.size()-1 : int(AmbientDimAtCompileTime); } - - /** normalizes \c *this */ - void normalize(void) - { - m_coeffs /= normal().norm(); - } - - /** \returns the signed distance between the plane \c *this and a point \a p. - * \sa absDistance() - */ - inline Scalar signedDistance(const VectorType& p) const { return p.eigen2_dot(normal()) + offset(); } - - /** \returns the absolute distance between the plane \c *this and a point \a p. - * \sa signedDistance() - */ - inline Scalar absDistance(const VectorType& p) const { return ei_abs(signedDistance(p)); } - - /** \returns the projection of a point \a p onto the plane \c *this. - */ - inline VectorType projection(const VectorType& p) const { return p - signedDistance(p) * normal(); } - - /** \returns a constant reference to the unit normal vector of the plane, which corresponds - * to the linear part of the implicit equation. - */ - inline const NormalReturnType normal() const { return NormalReturnType(*const_cast(&m_coeffs),0,0,dim(),1); } - - /** \returns a non-constant reference to the unit normal vector of the plane, which corresponds - * to the linear part of the implicit equation. - */ - inline NormalReturnType normal() { return NormalReturnType(m_coeffs,0,0,dim(),1); } - - /** \returns the distance to the origin, which is also the "constant term" of the implicit equation - * \warning the vector normal is assumed to be normalized. - */ - inline const Scalar& offset() const { return m_coeffs.coeff(dim()); } - - /** \returns a non-constant reference to the distance to the origin, which is also the constant part - * of the implicit equation */ - inline Scalar& offset() { return m_coeffs(dim()); } - - /** \returns a constant reference to the coefficients c_i of the plane equation: - * \f$ c_0*x_0 + ... + c_{d-1}*x_{d-1} + c_d = 0 \f$ - */ - inline const Coefficients& coeffs() const { return m_coeffs; } - - /** \returns a non-constant reference to the coefficients c_i of the plane equation: - * \f$ c_0*x_0 + ... + c_{d-1}*x_{d-1} + c_d = 0 \f$ - */ - inline Coefficients& coeffs() { return m_coeffs; } - - /** \returns the intersection of *this with \a other. - * - * \warning The ambient space must be a plane, i.e. have dimension 2, so that \c *this and \a other are lines. - * - * \note If \a other is approximately parallel to *this, this method will return any point on *this. - */ - VectorType intersection(const Hyperplane& other) - { - EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VectorType, 2) - Scalar det = coeffs().coeff(0) * other.coeffs().coeff(1) - coeffs().coeff(1) * other.coeffs().coeff(0); - // since the line equations ax+by=c are normalized with a^2+b^2=1, the following tests - // whether the two lines are approximately parallel. - if(ei_isMuchSmallerThan(det, Scalar(1))) - { // special case where the two lines are approximately parallel. Pick any point on the first line. - if(ei_abs(coeffs().coeff(1))>ei_abs(coeffs().coeff(0))) - return VectorType(coeffs().coeff(1), -coeffs().coeff(2)/coeffs().coeff(1)-coeffs().coeff(0)); - else - return VectorType(-coeffs().coeff(2)/coeffs().coeff(0)-coeffs().coeff(1), coeffs().coeff(0)); - } - else - { // general case - Scalar invdet = Scalar(1) / det; - return VectorType(invdet*(coeffs().coeff(1)*other.coeffs().coeff(2)-other.coeffs().coeff(1)*coeffs().coeff(2)), - invdet*(other.coeffs().coeff(0)*coeffs().coeff(2)-coeffs().coeff(0)*other.coeffs().coeff(2))); - } - } - - /** Applies the transformation matrix \a mat to \c *this and returns a reference to \c *this. - * - * \param mat the Dim x Dim transformation matrix - * \param traits specifies whether the matrix \a mat represents an Isometry - * or a more generic Affine transformation. The default is Affine. - */ - template - inline Hyperplane& transform(const MatrixBase& mat, TransformTraits traits = Affine) - { - if (traits==Affine) - normal() = mat.inverse().transpose() * normal(); - else if (traits==Isometry) - normal() = mat * normal(); - else - { - ei_assert("invalid traits value in Hyperplane::transform()"); - } - return *this; - } - - /** Applies the transformation \a t to \c *this and returns a reference to \c *this. - * - * \param t the transformation of dimension Dim - * \param traits specifies whether the transformation \a t represents an Isometry - * or a more generic Affine transformation. The default is Affine. - * Other kind of transformations are not supported. - */ - inline Hyperplane& transform(const Transform& t, - TransformTraits traits = Affine) - { - transform(t.linear(), traits); - offset() -= t.translation().eigen2_dot(normal()); - return *this; - } - - /** \returns \c *this with scalar type casted to \a NewScalarType - * - * Note that if \a NewScalarType is equal to the current scalar type of \c *this - * then this function smartly returns a const reference to \c *this. - */ - template - inline typename internal::cast_return_type >::type cast() const - { - return typename internal::cast_return_type >::type(*this); - } - - /** Copy constructor with scalar type conversion */ - template - inline explicit Hyperplane(const Hyperplane& other) - { m_coeffs = other.coeffs().template cast(); } - - /** \returns \c true if \c *this is approximately equal to \a other, within the precision - * determined by \a prec. - * - * \sa MatrixBase::isApprox() */ - bool isApprox(const Hyperplane& other, typename NumTraits::Real prec = precision()) const - { return m_coeffs.isApprox(other.m_coeffs, prec); } - -protected: - - Coefficients m_coeffs; -}; - -} // end namespace Eigen diff --git a/splinter/src/Eigen2Support/Geometry/ParametrizedLine.h b/splinter/src/Eigen2Support/Geometry/ParametrizedLine.h deleted file mode 100644 index 9b57b7e0bb..0000000000 --- a/splinter/src/Eigen2Support/Geometry/ParametrizedLine.h +++ /dev/null @@ -1,141 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2008 Benoit Jacob -// -// 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 ParametrizedLine - * - * \brief A parametrized line - * - * A parametrized line is defined by an origin point \f$ \mathbf{o} \f$ and a unit - * direction vector \f$ \mathbf{d} \f$ such that the line corresponds to - * the set \f$ l(t) = \mathbf{o} + t \mathbf{d} \f$, \f$ l \in \mathbf{R} \f$. - * - * \param _Scalar the scalar type, i.e., the type of the coefficients - * \param _AmbientDim the dimension of the ambient space, can be a compile time value or Dynamic. - */ -template -class ParametrizedLine -{ -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) - enum { AmbientDimAtCompileTime = _AmbientDim }; - typedef _Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix VectorType; - - /** Default constructor without initialization */ - inline ParametrizedLine() {} - - /** Constructs a dynamic-size line with \a _dim the dimension - * of the ambient space */ - inline explicit ParametrizedLine(int _dim) : m_origin(_dim), m_direction(_dim) {} - - /** Initializes a parametrized line of direction \a direction and origin \a origin. - * \warning the vector direction is assumed to be normalized. - */ - ParametrizedLine(const VectorType& origin, const VectorType& direction) - : m_origin(origin), m_direction(direction) {} - - explicit ParametrizedLine(const Hyperplane<_Scalar, _AmbientDim>& hyperplane); - - /** Constructs a parametrized line going from \a p0 to \a p1. */ - static inline ParametrizedLine Through(const VectorType& p0, const VectorType& p1) - { return ParametrizedLine(p0, (p1-p0).normalized()); } - - ~ParametrizedLine() {} - - /** \returns the dimension in which the line holds */ - inline int dim() const { return m_direction.size(); } - - const VectorType& origin() const { return m_origin; } - VectorType& origin() { return m_origin; } - - const VectorType& direction() const { return m_direction; } - VectorType& direction() { return m_direction; } - - /** \returns the squared distance of a point \a p to its projection onto the line \c *this. - * \sa distance() - */ - RealScalar squaredDistance(const VectorType& p) const - { - VectorType diff = p-origin(); - return (diff - diff.eigen2_dot(direction())* direction()).squaredNorm(); - } - /** \returns the distance of a point \a p to its projection onto the line \c *this. - * \sa squaredDistance() - */ - RealScalar distance(const VectorType& p) const { return ei_sqrt(squaredDistance(p)); } - - /** \returns the projection of a point \a p onto the line \c *this. */ - VectorType projection(const VectorType& p) const - { return origin() + (p-origin()).eigen2_dot(direction()) * direction(); } - - Scalar intersection(const Hyperplane<_Scalar, _AmbientDim>& hyperplane); - - /** \returns \c *this with scalar type casted to \a NewScalarType - * - * Note that if \a NewScalarType is equal to the current scalar type of \c *this - * then this function smartly returns a const reference to \c *this. - */ - template - inline typename internal::cast_return_type >::type cast() const - { - return typename internal::cast_return_type >::type(*this); - } - - /** Copy constructor with scalar type conversion */ - template - inline explicit ParametrizedLine(const ParametrizedLine& other) - { - m_origin = other.origin().template cast(); - m_direction = other.direction().template cast(); - } - - /** \returns \c true if \c *this is approximately equal to \a other, within the precision - * determined by \a prec. - * - * \sa MatrixBase::isApprox() */ - bool isApprox(const ParametrizedLine& other, typename NumTraits::Real prec = precision()) const - { return m_origin.isApprox(other.m_origin, prec) && m_direction.isApprox(other.m_direction, prec); } - -protected: - - VectorType m_origin, m_direction; -}; - -/** Constructs a parametrized line from a 2D hyperplane - * - * \warning the ambient space must have dimension 2 such that the hyperplane actually describes a line - */ -template -inline ParametrizedLine<_Scalar, _AmbientDim>::ParametrizedLine(const Hyperplane<_Scalar, _AmbientDim>& hyperplane) -{ - EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VectorType, 2) - direction() = hyperplane.normal().unitOrthogonal(); - origin() = -hyperplane.normal()*hyperplane.offset(); -} - -/** \returns the parameter value of the intersection between \c *this and the given hyperplane - */ -template -inline _Scalar ParametrizedLine<_Scalar, _AmbientDim>::intersection(const Hyperplane<_Scalar, _AmbientDim>& hyperplane) -{ - return -(hyperplane.offset()+origin().eigen2_dot(hyperplane.normal())) - /(direction().eigen2_dot(hyperplane.normal())); -} - -} // end namespace Eigen diff --git a/splinter/src/Eigen2Support/Geometry/Quaternion.h b/splinter/src/Eigen2Support/Geometry/Quaternion.h deleted file mode 100644 index 4b6390cf1d..0000000000 --- a/splinter/src/Eigen2Support/Geometry/Quaternion.h +++ /dev/null @@ -1,495 +0,0 @@ -// 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/. - -// no include guard, we'll include this twice from All.h from Eigen2Support, and it's internal anyway - -namespace Eigen { - -template -struct ei_quaternion_assign_impl; - -/** \geometry_module \ingroup Geometry_Module - * - * \class Quaternion - * - * \brief The quaternion class used to represent 3D orientations and rotations - * - * \param _Scalar the scalar type, i.e., the type of the coefficients - * - * This class represents a quaternion \f$ w+xi+yj+zk \f$ that is a convenient representation of - * orientations and rotations of objects in three dimensions. Compared to other representations - * like Euler angles or 3x3 matrices, quatertions offer the following advantages: - * \li \b compact storage (4 scalars) - * \li \b efficient to compose (28 flops), - * \li \b stable spherical interpolation - * - * The following two typedefs are provided for convenience: - * \li \c Quaternionf for \c float - * \li \c Quaterniond for \c double - * - * \sa class AngleAxis, class Transform - */ - -template struct ei_traits > -{ - typedef _Scalar Scalar; -}; - -template -class Quaternion : public RotationBase,3> -{ - typedef RotationBase,3> Base; - -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,4) - - using Base::operator*; - - /** the scalar type of the coefficients */ - typedef _Scalar Scalar; - - /** the type of the Coefficients 4-vector */ - typedef Matrix Coefficients; - /** the type of a 3D vector */ - typedef Matrix Vector3; - /** the equivalent rotation matrix type */ - typedef Matrix Matrix3; - /** the equivalent angle-axis type */ - typedef AngleAxis AngleAxisType; - - /** \returns the \c x coefficient */ - inline Scalar x() const { return m_coeffs.coeff(0); } - /** \returns the \c y coefficient */ - inline Scalar y() const { return m_coeffs.coeff(1); } - /** \returns the \c z coefficient */ - inline Scalar z() const { return m_coeffs.coeff(2); } - /** \returns the \c w coefficient */ - inline Scalar w() const { return m_coeffs.coeff(3); } - - /** \returns a reference to the \c x coefficient */ - inline Scalar& x() { return m_coeffs.coeffRef(0); } - /** \returns a reference to the \c y coefficient */ - inline Scalar& y() { return m_coeffs.coeffRef(1); } - /** \returns a reference to the \c z coefficient */ - inline Scalar& z() { return m_coeffs.coeffRef(2); } - /** \returns a reference to the \c w coefficient */ - inline Scalar& w() { return m_coeffs.coeffRef(3); } - - /** \returns a read-only vector expression of the imaginary part (x,y,z) */ - inline const Block vec() const { return m_coeffs.template start<3>(); } - - /** \returns a vector expression of the imaginary part (x,y,z) */ - inline Block vec() { return m_coeffs.template start<3>(); } - - /** \returns a read-only vector expression of the coefficients (x,y,z,w) */ - inline const Coefficients& coeffs() const { return m_coeffs; } - - /** \returns a vector expression of the coefficients (x,y,z,w) */ - inline Coefficients& coeffs() { return m_coeffs; } - - /** Default constructor leaving the quaternion uninitialized. */ - inline Quaternion() {} - - /** Constructs and initializes the quaternion \f$ w+xi+yj+zk \f$ from - * its four coefficients \a w, \a x, \a y and \a z. - * - * \warning Note the order of the arguments: the real \a w coefficient first, - * while internally the coefficients are stored in the following order: - * [\c x, \c y, \c z, \c w] - */ - inline Quaternion(Scalar w, Scalar x, Scalar y, Scalar z) - { m_coeffs << x, y, z, w; } - - /** Copy constructor */ - inline Quaternion(const Quaternion& other) { m_coeffs = other.m_coeffs; } - - /** Constructs and initializes a quaternion from the angle-axis \a aa */ - explicit inline Quaternion(const AngleAxisType& aa) { *this = aa; } - - /** Constructs and initializes a quaternion from either: - * - a rotation matrix expression, - * - a 4D vector expression representing quaternion coefficients. - * \sa operator=(MatrixBase) - */ - template - explicit inline Quaternion(const MatrixBase& other) { *this = other; } - - Quaternion& operator=(const Quaternion& other); - Quaternion& operator=(const AngleAxisType& aa); - template - Quaternion& operator=(const MatrixBase& m); - - /** \returns a quaternion representing an identity rotation - * \sa MatrixBase::Identity() - */ - static inline Quaternion Identity() { return Quaternion(1, 0, 0, 0); } - - /** \sa Quaternion::Identity(), MatrixBase::setIdentity() - */ - inline Quaternion& setIdentity() { m_coeffs << 0, 0, 0, 1; return *this; } - - /** \returns the squared norm of the quaternion's coefficients - * \sa Quaternion::norm(), MatrixBase::squaredNorm() - */ - inline Scalar squaredNorm() const { return m_coeffs.squaredNorm(); } - - /** \returns the norm of the quaternion's coefficients - * \sa Quaternion::squaredNorm(), MatrixBase::norm() - */ - inline Scalar norm() const { return m_coeffs.norm(); } - - /** Normalizes the quaternion \c *this - * \sa normalized(), MatrixBase::normalize() */ - inline void normalize() { m_coeffs.normalize(); } - /** \returns a normalized version of \c *this - * \sa normalize(), MatrixBase::normalized() */ - inline Quaternion normalized() const { return Quaternion(m_coeffs.normalized()); } - - /** \returns the dot product of \c *this and \a other - * Geometrically speaking, the dot product of two unit quaternions - * corresponds to the cosine of half the angle between the two rotations. - * \sa angularDistance() - */ - inline Scalar eigen2_dot(const Quaternion& other) const { return m_coeffs.eigen2_dot(other.m_coeffs); } - - inline Scalar angularDistance(const Quaternion& other) const; - - Matrix3 toRotationMatrix(void) const; - - template - Quaternion& setFromTwoVectors(const MatrixBase& a, const MatrixBase& b); - - inline Quaternion operator* (const Quaternion& q) const; - inline Quaternion& operator*= (const Quaternion& q); - - Quaternion inverse(void) const; - Quaternion conjugate(void) const; - - Quaternion slerp(Scalar t, const Quaternion& other) const; - - template - Vector3 operator* (const MatrixBase& vec) const; - - /** \returns \c *this with scalar type casted to \a NewScalarType - * - * Note that if \a NewScalarType is equal to the current scalar type of \c *this - * then this function smartly returns a const reference to \c *this. - */ - template - inline typename internal::cast_return_type >::type cast() const - { return typename internal::cast_return_type >::type(*this); } - - /** Copy constructor with scalar type conversion */ - template - inline explicit Quaternion(const Quaternion& other) - { m_coeffs = other.coeffs().template cast(); } - - /** \returns \c true if \c *this is approximately equal to \a other, within the precision - * determined by \a prec. - * - * \sa MatrixBase::isApprox() */ - bool isApprox(const Quaternion& other, typename NumTraits::Real prec = precision()) const - { return m_coeffs.isApprox(other.m_coeffs, prec); } - -protected: - Coefficients m_coeffs; -}; - -/** \ingroup Geometry_Module - * single precision quaternion type */ -typedef Quaternion Quaternionf; -/** \ingroup Geometry_Module - * double precision quaternion type */ -typedef Quaternion Quaterniond; - -// Generic Quaternion * Quaternion product -template inline Quaternion -ei_quaternion_product(const Quaternion& a, const Quaternion& b) -{ - return Quaternion - ( - a.w() * b.w() - a.x() * b.x() - a.y() * b.y() - a.z() * b.z(), - a.w() * b.x() + a.x() * b.w() + a.y() * b.z() - a.z() * b.y(), - a.w() * b.y() + a.y() * b.w() + a.z() * b.x() - a.x() * b.z(), - a.w() * b.z() + a.z() * b.w() + a.x() * b.y() - a.y() * b.x() - ); -} - -/** \returns the concatenation of two rotations as a quaternion-quaternion product */ -template -inline Quaternion Quaternion::operator* (const Quaternion& other) const -{ - return ei_quaternion_product(*this,other); -} - -/** \sa operator*(Quaternion) */ -template -inline Quaternion& Quaternion::operator*= (const Quaternion& other) -{ - return (*this = *this * other); -} - -/** Rotation of a vector by a quaternion. - * \remarks If the quaternion is used to rotate several points (>1) - * then it is much more efficient to first convert it to a 3x3 Matrix. - * Comparison of the operation cost for n transformations: - * - Quaternion: 30n - * - Via a Matrix3: 24 + 15n - */ -template -template -inline typename Quaternion::Vector3 -Quaternion::operator* (const MatrixBase& v) const -{ - // Note that this algorithm comes from the optimization by hand - // of the conversion to a Matrix followed by a Matrix/Vector product. - // It appears to be much faster than the common algorithm found - // in the litterature (30 versus 39 flops). It also requires two - // Vector3 as temporaries. - Vector3 uv; - uv = 2 * this->vec().cross(v); - return v + this->w() * uv + this->vec().cross(uv); -} - -template -inline Quaternion& Quaternion::operator=(const Quaternion& other) -{ - m_coeffs = other.m_coeffs; - return *this; -} - -/** Set \c *this from an angle-axis \a aa and returns a reference to \c *this - */ -template -inline Quaternion& Quaternion::operator=(const AngleAxisType& aa) -{ - Scalar ha = Scalar(0.5)*aa.angle(); // Scalar(0.5) to suppress precision loss warnings - this->w() = ei_cos(ha); - this->vec() = ei_sin(ha) * aa.axis(); - return *this; -} - -/** Set \c *this from the expression \a xpr: - * - if \a xpr is a 4x1 vector, then \a xpr is assumed to be a quaternion - * - if \a xpr is a 3x3 matrix, then \a xpr is assumed to be rotation matrix - * and \a xpr is converted to a quaternion - */ -template -template -inline Quaternion& Quaternion::operator=(const MatrixBase& xpr) -{ - ei_quaternion_assign_impl::run(*this, xpr.derived()); - return *this; -} - -/** Convert the quaternion to a 3x3 rotation matrix */ -template -inline typename Quaternion::Matrix3 -Quaternion::toRotationMatrix(void) const -{ - // NOTE if inlined, then gcc 4.2 and 4.4 get rid of the temporary (not gcc 4.3 !!) - // if not inlined then the cost of the return by value is huge ~ +35%, - // however, not inlining this function is an order of magnitude slower, so - // it has to be inlined, and so the return by value is not an issue - Matrix3 res; - - 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(); - const Scalar txx = tx*this->x(); - const Scalar txy = ty*this->x(); - const Scalar txz = tz*this->x(); - const Scalar tyy = ty*this->y(); - const Scalar tyz = tz*this->y(); - const Scalar tzz = tz*this->z(); - - 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) = 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) = Scalar(1)-(txx+tyy); - - return res; -} - -/** Sets *this to be a quaternion representing a rotation sending the vector \a a to the vector \a b. - * - * \returns a reference to *this. - * - * Note that the two input vectors do \b not have to be normalized. - */ -template -template -inline Quaternion& Quaternion::setFromTwoVectors(const MatrixBase& a, const MatrixBase& b) -{ - Vector3 v0 = a.normalized(); - Vector3 v1 = b.normalized(); - Scalar c = v0.eigen2_dot(v1); - - // if dot == 1, vectors are the same - if (ei_isApprox(c,Scalar(1))) - { - // set to identity - this->w() = 1; this->vec().setZero(); - return *this; - } - // if dot == -1, vectors are opposites - if (ei_isApprox(c,Scalar(-1))) - { - this->vec() = v0.unitOrthogonal(); - this->w() = 0; - return *this; - } - - Vector3 axis = v0.cross(v1); - Scalar s = ei_sqrt((Scalar(1)+c)*Scalar(2)); - Scalar invs = Scalar(1)/s; - this->vec() = axis * invs; - this->w() = s * Scalar(0.5); - - return *this; -} - -/** \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. - * - * \sa Quaternion::conjugate() - */ -template -inline Quaternion Quaternion::inverse() const -{ - // FIXME should this function be called multiplicativeInverse and conjugate() be called inverse() or opposite() ?? - Scalar n2 = this->squaredNorm(); - if (n2 > 0) - return Quaternion(conjugate().coeffs() / n2); - else - { - // return an invalid result to flag the error - return Quaternion(Coefficients::Zero()); - } -} - -/** \returns the conjugate of the \c *this which is equal to the multiplicative inverse - * if the quaternion is normalized. - * The conjugate of a quaternion represents the opposite rotation. - * - * \sa Quaternion::inverse() - */ -template -inline Quaternion Quaternion::conjugate() const -{ - return Quaternion(this->w(),-this->x(),-this->y(),-this->z()); -} - -/** \returns the angle (in radian) between two rotations - * \sa eigen2_dot() - */ -template -inline Scalar Quaternion::angularDistance(const Quaternion& other) const -{ - double d = ei_abs(this->eigen2_dot(other)); - if (d>=1.0) - return 0; - return Scalar(2) * std::acos(d); -} - -/** \returns the spherical linear interpolation between the two quaternions - * \c *this and \a other at the parameter \a t - */ -template -Quaternion Quaternion::slerp(Scalar t, const Quaternion& other) const -{ - static const Scalar one = Scalar(1) - machine_epsilon(); - Scalar d = this->eigen2_dot(other); - Scalar absD = ei_abs(d); - - Scalar scale0; - Scalar scale1; - - if (absD>=one) - { - scale0 = Scalar(1) - t; - scale1 = t; - } - else - { - // theta is the angle between the 2 quaternions - Scalar theta = std::acos(absD); - Scalar sinTheta = ei_sin(theta); - - scale0 = ei_sin( ( Scalar(1) - t ) * theta) / sinTheta; - scale1 = ei_sin( ( t * theta) ) / sinTheta; - if (d<0) - scale1 = -scale1; - } - - return Quaternion(scale0 * coeffs() + scale1 * other.coeffs()); -} - -// set from a rotation matrix -template -struct ei_quaternion_assign_impl -{ - typedef typename Other::Scalar Scalar; - static inline void run(Quaternion& q, const Other& mat) - { - // This algorithm comes from "Quaternion Calculus and Fast Animation", - // Ken Shoemake, 1987 SIGGRAPH course notes - Scalar t = mat.trace(); - if (t > 0) - { - t = ei_sqrt(t + Scalar(1.0)); - q.w() = Scalar(0.5)*t; - t = Scalar(0.5)/t; - q.x() = (mat.coeff(2,1) - mat.coeff(1,2)) * t; - q.y() = (mat.coeff(0,2) - mat.coeff(2,0)) * t; - q.z() = (mat.coeff(1,0) - mat.coeff(0,1)) * t; - } - else - { - int i = 0; - if (mat.coeff(1,1) > mat.coeff(0,0)) - i = 1; - if (mat.coeff(2,2) > mat.coeff(i,i)) - i = 2; - int j = (i+1)%3; - int k = (j+1)%3; - - t = ei_sqrt(mat.coeff(i,i)-mat.coeff(j,j)-mat.coeff(k,k) + Scalar(1.0)); - q.coeffs().coeffRef(i) = Scalar(0.5) * t; - t = Scalar(0.5)/t; - q.w() = (mat.coeff(k,j)-mat.coeff(j,k))*t; - q.coeffs().coeffRef(j) = (mat.coeff(j,i)+mat.coeff(i,j))*t; - q.coeffs().coeffRef(k) = (mat.coeff(k,i)+mat.coeff(i,k))*t; - } - } -}; - -// set from a vector of coefficients assumed to be a quaternion -template -struct ei_quaternion_assign_impl -{ - typedef typename Other::Scalar Scalar; - static inline void run(Quaternion& q, const Other& vec) - { - q.coeffs() = vec; - } -}; - -} // end namespace Eigen diff --git a/splinter/src/Eigen2Support/Geometry/Rotation2D.h b/splinter/src/Eigen2Support/Geometry/Rotation2D.h deleted file mode 100644 index 19b8582a1b..0000000000 --- a/splinter/src/Eigen2Support/Geometry/Rotation2D.h +++ /dev/null @@ -1,145 +0,0 @@ -// 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/. - -// 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 Rotation2D - * - * \brief Represents a rotation/orientation in a 2 dimensional space. - * - * \param _Scalar the scalar type, i.e., the type of the coefficients - * - * This class is equivalent to a single scalar representing a counter clock wise rotation - * as a single angle in radian. It provides some additional features such as the automatic - * conversion from/to a 2x2 rotation matrix. Moreover this class aims to provide a similar - * interface to Quaternion in order to facilitate the writing of generic algorithms - * dealing with rotations. - * - * \sa class Quaternion, class Transform - */ -template struct ei_traits > -{ - typedef _Scalar Scalar; -}; - -template -class Rotation2D : public RotationBase,2> -{ - typedef RotationBase,2> Base; - -public: - - using Base::operator*; - - enum { Dim = 2 }; - /** the scalar type of the coefficients */ - typedef _Scalar Scalar; - typedef Matrix Vector2; - typedef Matrix Matrix2; - -protected: - - Scalar m_angle; - -public: - - /** Construct a 2D counter clock wise rotation from the angle \a a in radian. */ - inline Rotation2D(Scalar a) : m_angle(a) {} - - /** \returns the rotation angle */ - inline Scalar angle() const { return m_angle; } - - /** \returns a read-write reference to the rotation angle */ - inline Scalar& angle() { return m_angle; } - - /** \returns the inverse rotation */ - inline Rotation2D inverse() const { return -m_angle; } - - /** Concatenates two rotations */ - inline Rotation2D operator*(const Rotation2D& other) const - { return m_angle + other.m_angle; } - - /** Concatenates two rotations */ - inline Rotation2D& operator*=(const Rotation2D& other) - { return m_angle += other.m_angle; return *this; } - - /** Applies the rotation to a 2D vector */ - Vector2 operator* (const Vector2& vec) const - { return toRotationMatrix() * vec; } - - template - Rotation2D& fromRotationMatrix(const MatrixBase& m); - Matrix2 toRotationMatrix(void) const; - - /** \returns the spherical interpolation between \c *this and \a other using - * parameter \a t. It is in fact equivalent to a linear interpolation. - */ - inline Rotation2D slerp(Scalar t, const Rotation2D& other) const - { return m_angle * (1-t) + other.angle() * t; } - - /** \returns \c *this with scalar type casted to \a NewScalarType - * - * Note that if \a NewScalarType is equal to the current scalar type of \c *this - * then this function smartly returns a const reference to \c *this. - */ - template - inline typename internal::cast_return_type >::type cast() const - { return typename internal::cast_return_type >::type(*this); } - - /** Copy constructor with scalar type conversion */ - template - inline explicit Rotation2D(const Rotation2D& other) - { - m_angle = Scalar(other.angle()); - } - - /** \returns \c true if \c *this is approximately equal to \a other, within the precision - * determined by \a prec. - * - * \sa MatrixBase::isApprox() */ - bool isApprox(const Rotation2D& other, typename NumTraits::Real prec = precision()) const - { return ei_isApprox(m_angle,other.m_angle, prec); } -}; - -/** \ingroup Geometry_Module - * single precision 2D rotation type */ -typedef Rotation2D Rotation2Df; -/** \ingroup Geometry_Module - * double precision 2D rotation type */ -typedef Rotation2D Rotation2Dd; - -/** Set \c *this from a 2x2 rotation matrix \a mat. - * In other words, this function extract the rotation angle - * from the rotation matrix. - */ -template -template -Rotation2D& Rotation2D::fromRotationMatrix(const MatrixBase& mat) -{ - EIGEN_STATIC_ASSERT(Derived::RowsAtCompileTime==2 && Derived::ColsAtCompileTime==2,YOU_MADE_A_PROGRAMMING_MISTAKE) - m_angle = ei_atan2(mat.coeff(1,0), mat.coeff(0,0)); - return *this; -} - -/** Constructs and \returns an equivalent 2x2 rotation matrix. - */ -template -typename Rotation2D::Matrix2 -Rotation2D::toRotationMatrix(void) const -{ - Scalar sinA = ei_sin(m_angle); - Scalar cosA = ei_cos(m_angle); - return (Matrix2() << cosA, -sinA, sinA, cosA).finished(); -} - -} // end namespace Eigen diff --git a/splinter/src/Eigen2Support/Geometry/RotationBase.h b/splinter/src/Eigen2Support/Geometry/RotationBase.h deleted file mode 100644 index b1c8f38da9..0000000000 --- a/splinter/src/Eigen2Support/Geometry/RotationBase.h +++ /dev/null @@ -1,123 +0,0 @@ -// 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/. - -// 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. - -/** \class RotationBase - * - * \brief Common base class for compact rotation representations - * - * \param Derived is the derived type, i.e., a rotation type - * \param _Dim the dimension of the space - */ -template -class RotationBase -{ - public: - enum { Dim = _Dim }; - /** the scalar type of the coefficients */ - typedef typename ei_traits::Scalar Scalar; - - /** corresponding linear transformation matrix type */ - typedef Matrix RotationMatrixType; - - inline const Derived& derived() const { return *static_cast(this); } - inline Derived& derived() { return *static_cast(this); } - - /** \returns an equivalent rotation matrix */ - inline RotationMatrixType toRotationMatrix() const { return derived().toRotationMatrix(); } - - /** \returns the inverse rotation */ - inline Derived inverse() const { return derived().inverse(); } - - /** \returns the concatenation of the rotation \c *this with a translation \a t */ - inline Transform operator*(const Translation& t) const - { return toRotationMatrix() * t; } - - /** \returns the concatenation of the rotation \c *this with a scaling \a s */ - inline RotationMatrixType operator*(const Scaling& s) const - { return toRotationMatrix() * s; } - - /** \returns the concatenation of the rotation \c *this with an affine transformation \a t */ - inline Transform operator*(const Transform& t) const - { return toRotationMatrix() * t; } -}; - -/** \geometry_module - * - * Constructs a Dim x Dim rotation matrix from the rotation \a r - */ -template -template -Matrix<_Scalar, _Rows, _Cols, _Storage, _MaxRows, _MaxCols> -::Matrix(const RotationBase& r) -{ - EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Matrix,int(OtherDerived::Dim),int(OtherDerived::Dim)) - *this = r.toRotationMatrix(); -} - -/** \geometry_module - * - * Set a Dim x Dim rotation matrix from the rotation \a r - */ -template -template -Matrix<_Scalar, _Rows, _Cols, _Storage, _MaxRows, _MaxCols>& -Matrix<_Scalar, _Rows, _Cols, _Storage, _MaxRows, _MaxCols> -::operator=(const RotationBase& r) -{ - EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Matrix,int(OtherDerived::Dim),int(OtherDerived::Dim)) - return *this = r.toRotationMatrix(); -} - -/** \internal - * - * Helper function to return an arbitrary rotation object to a rotation matrix. - * - * \param Scalar the numeric type of the matrix coefficients - * \param Dim the dimension of the current space - * - * It returns a Dim x Dim fixed size matrix. - * - * Default specializations are provided for: - * - any scalar type (2D), - * - any matrix expression, - * - any type based on RotationBase (e.g., Quaternion, AngleAxis, Rotation2D) - * - * Currently ei_toRotationMatrix is only used by Transform. - * - * \sa class Transform, class Rotation2D, class Quaternion, class AngleAxis - */ -template -static inline Matrix ei_toRotationMatrix(const Scalar& s) -{ - EIGEN_STATIC_ASSERT(Dim==2,YOU_MADE_A_PROGRAMMING_MISTAKE) - return Rotation2D(s).toRotationMatrix(); -} - -template -static inline Matrix ei_toRotationMatrix(const RotationBase& r) -{ - return r.toRotationMatrix(); -} - -template -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/splinter/src/Eigen2Support/Geometry/Scaling.h b/splinter/src/Eigen2Support/Geometry/Scaling.h deleted file mode 100644 index b8fa6cd3f6..0000000000 --- a/splinter/src/Eigen2Support/Geometry/Scaling.h +++ /dev/null @@ -1,167 +0,0 @@ -// 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/. - -// 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 Scaling - * - * \brief Represents a possibly non uniform scaling transformation - * - * \param _Scalar the scalar type, i.e., the type of the coefficients. - * \param _Dim the dimension of the space, can be a compile time value or Dynamic - * - * \note This class is not aimed to be used to store a scaling transformation, - * but rather to make easier the constructions and updates of Transform objects. - * - * \sa class Translation, class Transform - */ -template -class Scaling -{ -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_Dim) - /** dimension of the space */ - enum { Dim = _Dim }; - /** the scalar type of the coefficients */ - typedef _Scalar Scalar; - /** corresponding vector type */ - typedef Matrix VectorType; - /** corresponding linear transformation matrix type */ - typedef Matrix LinearMatrixType; - /** corresponding translation type */ - typedef Translation TranslationType; - /** corresponding affine transformation type */ - typedef Transform TransformType; - -protected: - - VectorType m_coeffs; - -public: - - /** Default constructor without initialization. */ - Scaling() {} - /** Constructs and initialize a uniform scaling transformation */ - explicit inline Scaling(const Scalar& s) { m_coeffs.setConstant(s); } - /** 2D only */ - inline Scaling(const Scalar& sx, const Scalar& sy) - { - ei_assert(Dim==2); - m_coeffs.x() = sx; - m_coeffs.y() = sy; - } - /** 3D only */ - inline Scaling(const Scalar& sx, const Scalar& sy, const Scalar& sz) - { - ei_assert(Dim==3); - m_coeffs.x() = sx; - m_coeffs.y() = sy; - m_coeffs.z() = sz; - } - /** Constructs and initialize the scaling transformation from a vector of scaling coefficients */ - explicit inline Scaling(const VectorType& coeffs) : m_coeffs(coeffs) {} - - const VectorType& coeffs() const { return m_coeffs; } - VectorType& coeffs() { return m_coeffs; } - - /** Concatenates two scaling */ - inline Scaling operator* (const Scaling& other) const - { return Scaling(coeffs().cwise() * other.coeffs()); } - - /** Concatenates a scaling and a translation */ - inline TransformType operator* (const TranslationType& t) const; - - /** Concatenates a scaling and an affine transformation */ - inline TransformType operator* (const TransformType& t) const; - - /** Concatenates a scaling and a linear transformation matrix */ - // TODO returns an expression - inline LinearMatrixType operator* (const LinearMatrixType& other) const - { return coeffs().asDiagonal() * other; } - - /** Concatenates a linear transformation matrix and a scaling */ - // TODO returns an expression - friend inline LinearMatrixType operator* (const LinearMatrixType& other, const Scaling& s) - { return other * s.coeffs().asDiagonal(); } - - template - inline LinearMatrixType operator*(const RotationBase& r) const - { return *this * r.toRotationMatrix(); } - - /** Applies scaling to vector */ - inline VectorType operator* (const VectorType& other) const - { return coeffs().asDiagonal() * other; } - - /** \returns the inverse scaling */ - inline Scaling inverse() const - { return Scaling(coeffs().cwise().inverse()); } - - inline Scaling& operator=(const Scaling& other) - { - m_coeffs = other.m_coeffs; - return *this; - } - - /** \returns \c *this with scalar type casted to \a NewScalarType - * - * Note that if \a NewScalarType is equal to the current scalar type of \c *this - * then this function smartly returns a const reference to \c *this. - */ - template - inline typename internal::cast_return_type >::type cast() const - { return typename internal::cast_return_type >::type(*this); } - - /** Copy constructor with scalar type conversion */ - template - inline explicit Scaling(const Scaling& other) - { m_coeffs = other.coeffs().template cast(); } - - /** \returns \c true if \c *this is approximately equal to \a other, within the precision - * determined by \a prec. - * - * \sa MatrixBase::isApprox() */ - bool isApprox(const Scaling& other, typename NumTraits::Real prec = precision()) const - { return m_coeffs.isApprox(other.m_coeffs, prec); } - -}; - -/** \addtogroup Geometry_Module */ -//@{ -typedef Scaling Scaling2f; -typedef Scaling Scaling2d; -typedef Scaling Scaling3f; -typedef Scaling Scaling3d; -//@} - -template -inline typename Scaling::TransformType -Scaling::operator* (const TranslationType& t) const -{ - TransformType res; - res.matrix().setZero(); - res.linear().diagonal() = coeffs(); - res.translation() = m_coeffs.cwise() * t.vector(); - res(Dim,Dim) = Scalar(1); - return res; -} - -template -inline typename Scaling::TransformType -Scaling::operator* (const TransformType& t) const -{ - TransformType res = t; - res.prescale(m_coeffs); - return res; -} - -} // end namespace Eigen diff --git a/splinter/src/Eigen2Support/Geometry/Transform.h b/splinter/src/Eigen2Support/Geometry/Transform.h deleted file mode 100644 index fab60b251d..0000000000 --- a/splinter/src/Eigen2Support/Geometry/Transform.h +++ /dev/null @@ -1,786 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2009 Benoit Jacob -// -// 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 -// specializations, it is not allowed to use Dim+1 instead of HDim. -template< typename Other, - int Dim, - int HDim, - int OtherRows=Other::RowsAtCompileTime, - int OtherCols=Other::ColsAtCompileTime> -struct ei_transform_product_impl; - -/** \geometry_module \ingroup Geometry_Module - * - * \class Transform - * - * \brief Represents an homogeneous transformation in a N dimensional space - * - * \param _Scalar the scalar type, i.e., the type of the coefficients - * \param _Dim the dimension of the space - * - * The homography is internally represented and stored as a (Dim+1)^2 matrix which - * is available through the matrix() method. - * - * Conversion methods from/to Qt's QMatrix and QTransform are available if the - * preprocessor token EIGEN_QT_SUPPORT is defined. - * - * \sa class Matrix, class Quaternion - */ -template -class Transform -{ -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_Dim==Dynamic ? Dynamic : (_Dim+1)*(_Dim+1)) - enum { - Dim = _Dim, ///< space dimension in which the transformation holds - HDim = _Dim+1 ///< size of a respective homogeneous vector - }; - /** the scalar type of the coefficients */ - typedef _Scalar Scalar; - /** type of the matrix used to represent the transformation */ - typedef Matrix MatrixType; - /** 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; - /** type of read/write reference to the linear part of the transformation */ - typedef const Block ConstLinearPart; - /** type of a vector */ - typedef Matrix VectorType; - /** type of a read/write reference to the translation part of the rotation */ - typedef Block TranslationPart; - /** type of a read/write reference to the translation part of the rotation */ - typedef const Block ConstTranslationPart; - /** corresponding translation type */ - typedef Translation TranslationType; - /** corresponding scaling transformation type */ - typedef Scaling ScalingType; - -protected: - - MatrixType m_matrix; - -public: - - /** Default constructor without initialization of the coefficients. */ - inline Transform() { } - - inline Transform(const Transform& other) - { - m_matrix = other.m_matrix; - } - - inline explicit Transform(const TranslationType& t) { *this = t; } - inline explicit Transform(const ScalingType& s) { *this = s; } - template - inline explicit Transform(const RotationBase& r) { *this = r; } - - inline Transform& operator=(const Transform& other) - { m_matrix = other.m_matrix; return *this; } - - template // MSVC 2005 will commit suicide if BigMatrix has a default value - struct construct_from_matrix - { - static inline void run(Transform *transform, const MatrixBase& other) - { - transform->matrix() = other; - } - }; - - template struct construct_from_matrix - { - static inline void run(Transform *transform, const MatrixBase& other) - { - transform->linear() = other; - transform->translation().setZero(); - transform->matrix()(Dim,Dim) = Scalar(1); - transform->matrix().template block<1,Dim>(Dim,0).setZero(); - } - }; - - /** Constructs and initializes a transformation from a Dim^2 or a (Dim+1)^2 matrix. */ - template - inline explicit Transform(const MatrixBase& other) - { - construct_from_matrix::run(this, other); - } - - /** Set \c *this from a (Dim+1)^2 matrix. */ - template - inline Transform& operator=(const MatrixBase& other) - { m_matrix = other; return *this; } - - #ifdef EIGEN_QT_SUPPORT - inline Transform(const QMatrix& other); - inline Transform& operator=(const QMatrix& other); - inline QMatrix toQMatrix(void) const; - inline Transform(const QTransform& other); - inline Transform& operator=(const QTransform& other); - inline QTransform toQTransform(void) const; - #endif - - /** shortcut for m_matrix(row,col); - * \sa MatrixBase::operaror(int,int) const */ - inline Scalar operator() (int row, int col) const { return m_matrix(row,col); } - /** shortcut for m_matrix(row,col); - * \sa MatrixBase::operaror(int,int) */ - inline Scalar& operator() (int row, int col) { return m_matrix(row,col); } - - /** \returns a read-only expression of the transformation matrix */ - inline const MatrixType& matrix() const { return m_matrix; } - /** \returns a writable expression of the transformation matrix */ - inline MatrixType& matrix() { return m_matrix; } - - /** \returns a read-only expression of the linear (linear) part of the transformation */ - inline ConstLinearPart linear() const { return m_matrix.template block(0,0); } - /** \returns a writable expression of the linear (linear) part of the transformation */ - inline LinearPart linear() { return m_matrix.template block(0,0); } - - /** \returns a read-only expression of the translation vector of the transformation */ - inline ConstTranslationPart translation() const { return m_matrix.template block(0,Dim); } - /** \returns a writable expression of the translation vector of the transformation */ - inline TranslationPart translation() { return m_matrix.template block(0,Dim); } - - /** \returns an expression of the product between the transform \c *this and a matrix expression \a other - * - * The right hand side \a other might be either: - * \li a vector of size Dim, - * \li an homogeneous vector of size Dim+1, - * \li a transformation matrix of size Dim+1 x Dim+1. - */ - // note: this function is defined here because some compilers cannot find the respective declaration - template - inline const typename ei_transform_product_impl::ResultType - operator * (const MatrixBase &other) const - { return ei_transform_product_impl::run(*this,other.derived()); } - - /** \returns the product expression of a transformation matrix \a a times a transform \a b - * The transformation matrix \a a must have a Dim+1 x Dim+1 sizes. */ - template - friend inline const typename ProductReturnType::Type - operator * (const MatrixBase &a, const Transform &b) - { return a.derived() * b.matrix(); } - - /** Contatenates two transformations */ - inline const Transform - operator * (const Transform& other) const - { return Transform(m_matrix * other.matrix()); } - - /** \sa MatrixBase::setIdentity() */ - void setIdentity() { m_matrix.setIdentity(); } - static const typename MatrixType::IdentityReturnType Identity() - { - return MatrixType::Identity(); - } - - template - inline Transform& scale(const MatrixBase &other); - - template - inline Transform& prescale(const MatrixBase &other); - - inline Transform& scale(Scalar s); - inline Transform& prescale(Scalar s); - - template - inline Transform& translate(const MatrixBase &other); - - template - inline Transform& pretranslate(const MatrixBase &other); - - template - inline Transform& rotate(const RotationType& rotation); - - template - inline Transform& prerotate(const RotationType& rotation); - - Transform& shear(Scalar sx, Scalar sy); - Transform& preshear(Scalar sx, Scalar sy); - - inline Transform& operator=(const TranslationType& t); - inline Transform& operator*=(const TranslationType& t) { return translate(t.vector()); } - inline Transform operator*(const TranslationType& t) const; - - inline Transform& operator=(const ScalingType& t); - inline Transform& operator*=(const ScalingType& s) { return scale(s.coeffs()); } - inline Transform operator*(const ScalingType& s) const; - friend inline Transform operator*(const LinearMatrixType& mat, const Transform& t) - { - Transform res = t; - res.matrix().row(Dim) = t.matrix().row(Dim); - res.matrix().template block(0,0) = (mat * t.matrix().template block(0,0)).lazy(); - return res; - } - - template - inline Transform& operator=(const RotationBase& r); - template - inline Transform& operator*=(const RotationBase& r) { return rotate(r.toRotationMatrix()); } - template - inline Transform operator*(const RotationBase& r) const; - - LinearMatrixType rotation() const; - template - void computeRotationScaling(RotationMatrixType *rotation, ScalingMatrixType *scaling) const; - template - void computeScalingRotation(ScalingMatrixType *scaling, RotationMatrixType *rotation) const; - - template - Transform& fromPositionOrientationScale(const MatrixBase &position, - const OrientationType& orientation, const MatrixBase &scale); - - inline const MatrixType inverse(TransformTraits traits = Affine) const; - - /** \returns a const pointer to the column major internal matrix */ - const Scalar* data() const { return m_matrix.data(); } - /** \returns a non-const pointer to the column major internal matrix */ - Scalar* data() { return m_matrix.data(); } - - /** \returns \c *this with scalar type casted to \a NewScalarType - * - * Note that if \a NewScalarType is equal to the current scalar type of \c *this - * then this function smartly returns a const reference to \c *this. - */ - template - inline typename internal::cast_return_type >::type cast() const - { return typename internal::cast_return_type >::type(*this); } - - /** Copy constructor with scalar type conversion */ - template - inline explicit Transform(const Transform& other) - { m_matrix = other.matrix().template cast(); } - - /** \returns \c true if \c *this is approximately equal to \a other, within the precision - * determined by \a prec. - * - * \sa MatrixBase::isApprox() */ - bool isApprox(const Transform& other, typename NumTraits::Real prec = precision()) const - { return m_matrix.isApprox(other.m_matrix, prec); } - - #ifdef EIGEN_TRANSFORM_PLUGIN - #include EIGEN_TRANSFORM_PLUGIN - #endif - -protected: - -}; - -/** \ingroup Geometry_Module */ -typedef Transform Transform2f; -/** \ingroup Geometry_Module */ -typedef Transform Transform3f; -/** \ingroup Geometry_Module */ -typedef Transform Transform2d; -/** \ingroup Geometry_Module */ -typedef Transform Transform3d; - -/************************** -*** Optional QT support *** -**************************/ - -#ifdef EIGEN_QT_SUPPORT -/** Initialises \c *this from a QMatrix assuming the dimension is 2. - * - * This function is available only if the token EIGEN_QT_SUPPORT is defined. - */ -template -Transform::Transform(const QMatrix& other) -{ - *this = other; -} - -/** Set \c *this from a QMatrix assuming the dimension is 2. - * - * This function is available only if the token EIGEN_QT_SUPPORT is defined. - */ -template -Transform& Transform::operator=(const QMatrix& other) -{ - EIGEN_STATIC_ASSERT(Dim==2, YOU_MADE_A_PROGRAMMING_MISTAKE) - m_matrix << other.m11(), other.m21(), other.dx(), - other.m12(), other.m22(), other.dy(), - 0, 0, 1; - return *this; -} - -/** \returns a QMatrix from \c *this assuming the dimension is 2. - * - * \warning this convertion might loss data if \c *this is not affine - * - * This function is available only if the token EIGEN_QT_SUPPORT is defined. - */ -template -QMatrix Transform::toQMatrix(void) const -{ - EIGEN_STATIC_ASSERT(Dim==2, YOU_MADE_A_PROGRAMMING_MISTAKE) - return QMatrix(m_matrix.coeff(0,0), m_matrix.coeff(1,0), - m_matrix.coeff(0,1), m_matrix.coeff(1,1), - m_matrix.coeff(0,2), m_matrix.coeff(1,2)); -} - -/** Initialises \c *this from a QTransform assuming the dimension is 2. - * - * This function is available only if the token EIGEN_QT_SUPPORT is defined. - */ -template -Transform::Transform(const QTransform& other) -{ - *this = other; -} - -/** Set \c *this from a QTransform assuming the dimension is 2. - * - * This function is available only if the token EIGEN_QT_SUPPORT is defined. - */ -template -Transform& Transform::operator=(const QTransform& other) -{ - EIGEN_STATIC_ASSERT(Dim==2, YOU_MADE_A_PROGRAMMING_MISTAKE) - m_matrix << other.m11(), other.m21(), other.dx(), - other.m12(), other.m22(), other.dy(), - other.m13(), other.m23(), other.m33(); - return *this; -} - -/** \returns a QTransform from \c *this assuming the dimension is 2. - * - * This function is available only if the token EIGEN_QT_SUPPORT is defined. - */ -template -QTransform Transform::toQTransform(void) const -{ - EIGEN_STATIC_ASSERT(Dim==2, YOU_MADE_A_PROGRAMMING_MISTAKE) - return QTransform(m_matrix.coeff(0,0), m_matrix.coeff(1,0), m_matrix.coeff(2,0), - m_matrix.coeff(0,1), m_matrix.coeff(1,1), m_matrix.coeff(2,1), - m_matrix.coeff(0,2), m_matrix.coeff(1,2), m_matrix.coeff(2,2)); -} -#endif - -/********************* -*** Procedural API *** -*********************/ - -/** Applies on the right the non uniform scale transformation represented - * by the vector \a other to \c *this and returns a reference to \c *this. - * \sa prescale() - */ -template -template -Transform& -Transform::scale(const MatrixBase &other) -{ - EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim)) - linear() = (linear() * other.asDiagonal()).lazy(); - return *this; -} - -/** Applies on the right a uniform scale of a factor \a c to \c *this - * and returns a reference to \c *this. - * \sa prescale(Scalar) - */ -template -inline Transform& Transform::scale(Scalar s) -{ - linear() *= s; - return *this; -} - -/** Applies on the left the non uniform scale transformation represented - * by the vector \a other to \c *this and returns a reference to \c *this. - * \sa scale() - */ -template -template -Transform& -Transform::prescale(const MatrixBase &other) -{ - EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim)) - m_matrix.template block(0,0) = (other.asDiagonal() * m_matrix.template block(0,0)).lazy(); - return *this; -} - -/** Applies on the left a uniform scale of a factor \a c to \c *this - * and returns a reference to \c *this. - * \sa scale(Scalar) - */ -template -inline Transform& Transform::prescale(Scalar s) -{ - m_matrix.template corner(TopLeft) *= s; - return *this; -} - -/** Applies on the right the translation matrix represented by the vector \a other - * to \c *this and returns a reference to \c *this. - * \sa pretranslate() - */ -template -template -Transform& -Transform::translate(const MatrixBase &other) -{ - EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim)) - translation() += linear() * other; - return *this; -} - -/** Applies on the left the translation matrix represented by the vector \a other - * to \c *this and returns a reference to \c *this. - * \sa translate() - */ -template -template -Transform& -Transform::pretranslate(const MatrixBase &other) -{ - EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim)) - translation() += other; - return *this; -} - -/** Applies on the right the rotation represented by the rotation \a rotation - * to \c *this and returns a reference to \c *this. - * - * The template parameter \a RotationType is the type of the rotation which - * must be known by ei_toRotationMatrix<>. - * - * Natively supported types includes: - * - any scalar (2D), - * - a Dim x Dim matrix expression, - * - a Quaternion (3D), - * - a AngleAxis (3D) - * - * This mechanism is easily extendable to support user types such as Euler angles, - * or a pair of Quaternion for 4D rotations. - * - * \sa rotate(Scalar), class Quaternion, class AngleAxis, prerotate(RotationType) - */ -template -template -Transform& -Transform::rotate(const RotationType& rotation) -{ - linear() *= ei_toRotationMatrix(rotation); - return *this; -} - -/** Applies on the left the rotation represented by the rotation \a rotation - * to \c *this and returns a reference to \c *this. - * - * See rotate() for further details. - * - * \sa rotate() - */ -template -template -Transform& -Transform::prerotate(const RotationType& rotation) -{ - m_matrix.template block(0,0) = ei_toRotationMatrix(rotation) - * m_matrix.template block(0,0); - return *this; -} - -/** Applies on the right the shear transformation represented - * by the vector \a other to \c *this and returns a reference to \c *this. - * \warning 2D only. - * \sa preshear() - */ -template -Transform& -Transform::shear(Scalar sx, Scalar sy) -{ - EIGEN_STATIC_ASSERT(int(Dim)==2, YOU_MADE_A_PROGRAMMING_MISTAKE) - VectorType tmp = linear().col(0)*sy + linear().col(1); - linear() << linear().col(0) + linear().col(1)*sx, tmp; - return *this; -} - -/** Applies on the left the shear transformation represented - * by the vector \a other to \c *this and returns a reference to \c *this. - * \warning 2D only. - * \sa shear() - */ -template -Transform& -Transform::preshear(Scalar sx, Scalar sy) -{ - EIGEN_STATIC_ASSERT(int(Dim)==2, YOU_MADE_A_PROGRAMMING_MISTAKE) - m_matrix.template block(0,0) = LinearMatrixType(1, sx, sy, 1) * m_matrix.template block(0,0); - return *this; -} - -/****************************************************** -*** Scaling, Translation and Rotation compatibility *** -******************************************************/ - -template -inline Transform& Transform::operator=(const TranslationType& t) -{ - linear().setIdentity(); - translation() = t.vector(); - m_matrix.template block<1,Dim>(Dim,0).setZero(); - m_matrix(Dim,Dim) = Scalar(1); - return *this; -} - -template -inline Transform Transform::operator*(const TranslationType& t) const -{ - Transform res = *this; - res.translate(t.vector()); - return res; -} - -template -inline Transform& Transform::operator=(const ScalingType& s) -{ - m_matrix.setZero(); - linear().diagonal() = s.coeffs(); - m_matrix.coeffRef(Dim,Dim) = Scalar(1); - return *this; -} - -template -inline Transform Transform::operator*(const ScalingType& s) const -{ - Transform res = *this; - res.scale(s.coeffs()); - return res; -} - -template -template -inline Transform& Transform::operator=(const RotationBase& r) -{ - linear() = ei_toRotationMatrix(r); - translation().setZero(); - m_matrix.template block<1,Dim>(Dim,0).setZero(); - m_matrix.coeffRef(Dim,Dim) = Scalar(1); - return *this; -} - -template -template -inline Transform Transform::operator*(const RotationBase& r) const -{ - Transform res = *this; - res.rotate(r.derived()); - return res; -} - -/************************ -*** Special functions *** -************************/ - -/** \returns the rotation part of the transformation - * \nonstableyet - * - * \svd_module - * - * \sa computeRotationScaling(), computeScalingRotation(), class SVD - */ -template -typename Transform::LinearMatrixType -Transform::rotation() const -{ - LinearMatrixType result; - computeRotationScaling(&result, (LinearMatrixType*)0); - return result; -} - - -/** decomposes the linear part of the transformation as a product rotation x scaling, the scaling being - * not necessarily positive. - * - * If either pointer is zero, the corresponding computation is skipped. - * - * \nonstableyet - * - * \svd_module - * - * \sa computeScalingRotation(), rotation(), class SVD - */ -template -template -void Transform::computeRotationScaling(RotationMatrixType *rotation, ScalingMatrixType *scaling) const -{ - JacobiSVD svd(linear(), ComputeFullU|ComputeFullV); - Scalar x = (svd.matrixU() * svd.matrixV().adjoint()).determinant(); // so x has absolute value 1 - Matrix sv(svd.singularValues()); - sv.coeffRef(0) *= x; - if(scaling) - { - scaling->noalias() = svd.matrixV() * sv.asDiagonal() * svd.matrixV().adjoint(); - } - if(rotation) - { - LinearMatrixType m(svd.matrixU()); - m.col(0) /= x; - rotation->noalias() = m * svd.matrixV().adjoint(); - } -} - -/** decomposes the linear part of the transformation as a product rotation x scaling, the scaling being - * not necessarily positive. - * - * If either pointer is zero, the corresponding computation is skipped. - * - * \nonstableyet - * - * \svd_module - * - * \sa computeRotationScaling(), rotation(), class SVD - */ -template -template -void Transform::computeScalingRotation(ScalingMatrixType *scaling, RotationMatrixType *rotation) const -{ - JacobiSVD svd(linear(), ComputeFullU|ComputeFullV); - Scalar x = (svd.matrixU() * svd.matrixV().adjoint()).determinant(); // so x has absolute value 1 - Matrix sv(svd.singularValues()); - sv.coeffRef(0) *= x; - if(scaling) - { - scaling->noalias() = svd.matrixU() * sv.asDiagonal() * svd.matrixU().adjoint(); - } - if(rotation) - { - LinearMatrixType m(svd.matrixU()); - m.col(0) /= x; - rotation->noalias() = m * svd.matrixV().adjoint(); - } -} - -/** Convenient method to set \c *this from a position, orientation and scale - * of a 3D object. - */ -template -template -Transform& -Transform::fromPositionOrientationScale(const MatrixBase &position, - const OrientationType& orientation, const MatrixBase &scale) -{ - linear() = ei_toRotationMatrix(orientation); - linear() *= scale.asDiagonal(); - translation() = position; - m_matrix.template block<1,Dim>(Dim,0).setZero(); - m_matrix(Dim,Dim) = Scalar(1); - return *this; -} - -/** \nonstableyet - * - * \returns the inverse transformation matrix according to some given knowledge - * on \c *this. - * - * \param traits allows to optimize the inversion process when the transformion - * is known to be not a general transformation. The possible values are: - * - Projective if the transformation is not necessarily affine, i.e., if the - * last row is not guaranteed to be [0 ... 0 1] - * - Affine is the default, the last row is assumed to be [0 ... 0 1] - * - Isometry if the transformation is only a concatenations of translations - * and rotations. - * - * \warning unless \a traits is always set to NoShear or NoScaling, this function - * requires the generic inverse method of MatrixBase defined in the LU module. If - * you forget to include this module, then you will get hard to debug linking errors. - * - * \sa MatrixBase::inverse() - */ -template -inline const typename Transform::MatrixType -Transform::inverse(TransformTraits traits) const -{ - if (traits == Projective) - { - return m_matrix.inverse(); - } - else - { - MatrixType res; - if (traits == Affine) - { - res.template corner(TopLeft) = linear().inverse(); - } - else if (traits == Isometry) - { - res.template corner(TopLeft) = linear().transpose(); - } - else - { - ei_assert("invalid traits value in Transform::inverse()"); - } - // translation and remaining parts - res.template corner(TopRight) = - res.template corner(TopLeft) * translation(); - res.template corner<1,Dim>(BottomLeft).setZero(); - res.coeffRef(Dim,Dim) = Scalar(1); - return res; - } -} - -/***************************************************** -*** Specializations of operator* with a MatrixBase *** -*****************************************************/ - -template -struct ei_transform_product_impl -{ - typedef Transform TransformType; - typedef typename TransformType::MatrixType MatrixType; - typedef typename ProductReturnType::Type ResultType; - static ResultType run(const TransformType& tr, const Other& other) - { return tr.matrix() * other; } -}; - -template -struct ei_transform_product_impl -{ - typedef Transform TransformType; - typedef typename TransformType::MatrixType MatrixType; - typedef TransformType ResultType; - static ResultType run(const TransformType& tr, const Other& other) - { - TransformType res; - res.translation() = tr.translation(); - res.matrix().row(Dim) = tr.matrix().row(Dim); - res.linear() = (tr.linear() * other).lazy(); - return res; - } -}; - -template -struct ei_transform_product_impl -{ - typedef Transform TransformType; - typedef typename TransformType::MatrixType MatrixType; - typedef typename ProductReturnType::Type ResultType; - static ResultType run(const TransformType& tr, const Other& other) - { return tr.matrix() * other; } -}; - -template -struct ei_transform_product_impl -{ - typedef typename Other::Scalar Scalar; - typedef Transform TransformType; - typedef Matrix ResultType; - static ResultType run(const TransformType& tr, const Other& other) - { 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/splinter/src/Eigen2Support/Geometry/Translation.h b/splinter/src/Eigen2Support/Geometry/Translation.h deleted file mode 100644 index 2b9859f6f4..0000000000 --- a/splinter/src/Eigen2Support/Geometry/Translation.h +++ /dev/null @@ -1,184 +0,0 @@ -// 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/. - -// 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 Translation - * - * \brief Represents a translation transformation - * - * \param _Scalar the scalar type, i.e., the type of the coefficients. - * \param _Dim the dimension of the space, can be a compile time value or Dynamic - * - * \note This class is not aimed to be used to store a translation transformation, - * but rather to make easier the constructions and updates of Transform objects. - * - * \sa class Scaling, class Transform - */ -template -class Translation -{ -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_Dim) - /** dimension of the space */ - enum { Dim = _Dim }; - /** the scalar type of the coefficients */ - typedef _Scalar Scalar; - /** corresponding vector type */ - typedef Matrix VectorType; - /** corresponding linear transformation matrix type */ - typedef Matrix LinearMatrixType; - /** corresponding scaling transformation type */ - typedef Scaling ScalingType; - /** corresponding affine transformation type */ - typedef Transform TransformType; - -protected: - - VectorType m_coeffs; - -public: - - /** Default constructor without initialization. */ - Translation() {} - /** */ - inline Translation(const Scalar& sx, const Scalar& sy) - { - ei_assert(Dim==2); - m_coeffs.x() = sx; - m_coeffs.y() = sy; - } - /** */ - inline Translation(const Scalar& sx, const Scalar& sy, const Scalar& sz) - { - ei_assert(Dim==3); - m_coeffs.x() = sx; - m_coeffs.y() = sy; - m_coeffs.z() = sz; - } - /** Constructs and initialize the scaling transformation from a vector of scaling coefficients */ - explicit inline Translation(const VectorType& vector) : m_coeffs(vector) {} - - const VectorType& vector() const { return m_coeffs; } - VectorType& vector() { return m_coeffs; } - - /** Concatenates two translation */ - inline Translation operator* (const Translation& other) const - { return Translation(m_coeffs + other.m_coeffs); } - - /** Concatenates a translation and a scaling */ - inline TransformType operator* (const ScalingType& other) const; - - /** Concatenates a translation and a linear transformation */ - inline TransformType operator* (const LinearMatrixType& linear) const; - - template - inline TransformType operator*(const RotationBase& r) const - { return *this * r.toRotationMatrix(); } - - /** Concatenates a linear transformation and a translation */ - // its a nightmare to define a templated friend function outside its declaration - friend inline TransformType operator* (const LinearMatrixType& linear, const Translation& t) - { - TransformType res; - res.matrix().setZero(); - res.linear() = linear; - res.translation() = linear * t.m_coeffs; - res.matrix().row(Dim).setZero(); - res(Dim,Dim) = Scalar(1); - return res; - } - - /** Concatenates a translation and an affine transformation */ - inline TransformType operator* (const TransformType& t) const; - - /** Applies translation to vector */ - inline VectorType operator* (const VectorType& other) const - { return m_coeffs + other; } - - /** \returns the inverse translation (opposite) */ - Translation inverse() const { return Translation(-m_coeffs); } - - Translation& operator=(const Translation& other) - { - m_coeffs = other.m_coeffs; - return *this; - } - - /** \returns \c *this with scalar type casted to \a NewScalarType - * - * Note that if \a NewScalarType is equal to the current scalar type of \c *this - * then this function smartly returns a const reference to \c *this. - */ - template - inline typename internal::cast_return_type >::type cast() const - { return typename internal::cast_return_type >::type(*this); } - - /** Copy constructor with scalar type conversion */ - template - inline explicit Translation(const Translation& other) - { m_coeffs = other.vector().template cast(); } - - /** \returns \c true if \c *this is approximately equal to \a other, within the precision - * determined by \a prec. - * - * \sa MatrixBase::isApprox() */ - bool isApprox(const Translation& other, typename NumTraits::Real prec = precision()) const - { return m_coeffs.isApprox(other.m_coeffs, prec); } - -}; - -/** \addtogroup Geometry_Module */ -//@{ -typedef Translation Translation2f; -typedef Translation Translation2d; -typedef Translation Translation3f; -typedef Translation Translation3d; -//@} - - -template -inline typename Translation::TransformType -Translation::operator* (const ScalingType& other) const -{ - TransformType res; - res.matrix().setZero(); - res.linear().diagonal() = other.coeffs(); - res.translation() = m_coeffs; - res(Dim,Dim) = Scalar(1); - return res; -} - -template -inline typename Translation::TransformType -Translation::operator* (const LinearMatrixType& linear) const -{ - TransformType res; - res.matrix().setZero(); - res.linear() = linear; - res.translation() = m_coeffs; - res.matrix().row(Dim).setZero(); - res(Dim,Dim) = Scalar(1); - return res; -} - -template -inline typename Translation::TransformType -Translation::operator* (const TransformType& t) const -{ - TransformType res = t; - res.pretranslate(m_coeffs); - return res; -} - -} // end namespace Eigen diff --git a/splinter/src/Eigen2Support/LU.h b/splinter/src/Eigen2Support/LU.h deleted file mode 100644 index 49f19ad76e..0000000000 --- a/splinter/src/Eigen2Support/LU.h +++ /dev/null @@ -1,120 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2011 Benoit Jacob -// -// 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 -{ - public: - - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix IntRowVectorType; - typedef Matrix IntColVectorType; - typedef Matrix RowVectorType; - typedef Matrix ColVectorType; - - typedef Matrix KernelResultType; - - typedef Matrix ImageResultType; - - typedef FullPivLU Base; - - template - explicit LU(const T& t) : Base(t), m_originalMatrix(t) {} - - template - bool solve(const MatrixBase& b, ResultType *result) const - { - *result = static_cast(this)->solve(b); - return true; - } - - template - inline void computeInverse(ResultType *result) const - { - solve(MatrixType::Identity(this->rows(), this->cols()), result); - } - - template - void computeKernel(KernelMatrixType *result) const - { - *result = static_cast(this)->kernel(); - } - - template - void computeImage(ImageMatrixType *result) const - { - *result = static_cast(this)->image(m_originalMatrix); - } - - const ImageResultType image() const - { - return static_cast(this)->image(m_originalMatrix); - } - - const MatrixType& m_originalMatrix; -}; - -#if EIGEN2_SUPPORT_STAGE < STAGE20_RESOLVE_API_CONFLICTS -/** \lu_module - * - * Synonym of partialPivLu(). - * - * \return the partial-pivoting LU decomposition of \c *this. - * - * \sa class PartialPivLU - */ -template -inline const LU::PlainObject> -MatrixBase::lu() const -{ - return LU(eval()); -} -#endif - -#ifdef EIGEN2_SUPPORT -/** \lu_module - * - * Synonym of partialPivLu(). - * - * \return the partial-pivoting LU decomposition of \c *this. - * - * \sa class PartialPivLU - */ -template -inline const LU::PlainObject> -MatrixBase::eigen2_lu() const -{ - return LU(eval()); -} -#endif - -} // end namespace Eigen - -#endif // EIGEN2_LU_H diff --git a/splinter/src/Eigen2Support/Lazy.h b/splinter/src/Eigen2Support/Lazy.h deleted file mode 100644 index 593fc78e6d..0000000000 --- a/splinter/src/Eigen2Support/Lazy.h +++ /dev/null @@ -1,71 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Benoit Jacob -// -// 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 - * - * Example: \include MatrixBase_marked.cpp - * Output: \verbinclude MatrixBase_marked.out - * - * \sa class Flagged, extract(), part() - */ -template -template -inline const Flagged -MatrixBase::marked() const -{ - return derived(); -} - -/** \deprecated use MatrixBase::noalias() - * - * \returns an expression of *this with the EvalBeforeAssigningBit flag removed. - * - * Example: \include MatrixBase_lazy.cpp - * Output: \verbinclude MatrixBase_lazy.out - * - * \sa class Flagged, marked() - */ -template -inline const Flagged -MatrixBase::lazy() const -{ - return derived(); -} - - -/** \internal - * Overloaded to perform an efficient C += (A*B).lazy() */ -template -template -Derived& MatrixBase::operator+=(const Flagged, 0, - EvalBeforeAssigningBit>& other) -{ - other._expression().derived().addTo(derived()); return derived(); -} - -/** \internal - * Overloaded to perform an efficient C -= (A*B).lazy() */ -template -template -Derived& MatrixBase::operator-=(const Flagged, 0, - EvalBeforeAssigningBit>& other) -{ - other._expression().derived().subTo(derived()); return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_LAZY_H diff --git a/splinter/src/Eigen2Support/LeastSquares.h b/splinter/src/Eigen2Support/LeastSquares.h deleted file mode 100644 index 7992d49442..0000000000 --- a/splinter/src/Eigen2Support/LeastSquares.h +++ /dev/null @@ -1,169 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2009 Benoit Jacob -// -// 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 - * - * For a set of points, this function tries to express - * one of the coords as a linear (affine) function of the other coords. - * - * This is best explained by an example. This function works in full - * generality, for points in a space of arbitrary dimension, and also over - * the complex numbers, but for this example we will work in dimension 3 - * over the real numbers (doubles). - * - * So let us work with the following set of 5 points given by their - * \f$(x,y,z)\f$ coordinates: - * @code - Vector3d points[5]; - points[0] = Vector3d( 3.02, 6.89, -4.32 ); - points[1] = Vector3d( 2.01, 5.39, -3.79 ); - points[2] = Vector3d( 2.41, 6.01, -4.01 ); - points[3] = Vector3d( 2.09, 5.55, -3.86 ); - points[4] = Vector3d( 2.58, 6.32, -4.10 ); - * @endcode - * Suppose that we want to express the second coordinate (\f$y\f$) as a linear - * expression in \f$x\f$ and \f$z\f$, that is, - * \f[ y=ax+bz+c \f] - * for some constants \f$a,b,c\f$. Thus, we want to find the best possible - * constants \f$a,b,c\f$ so that the plane of equation \f$y=ax+bz+c\f$ fits - * best the five above points. To do that, call this function as follows: - * @code - Vector3d coeffs; // will store the coefficients a, b, c - linearRegression( - 5, - &points, - &coeffs, - 1 // the coord to express as a function of - // the other ones. 0 means x, 1 means y, 2 means z. - ); - * @endcode - * Now the vector \a coeffs is approximately - * \f$( 0.495 , -1.927 , -2.906 )\f$. - * Thus, we get \f$a=0.495, b = -1.927, c = -2.906\f$. Let us check for - * instance how near points[0] is from the plane of equation \f$y=ax+bz+c\f$. - * Looking at the coords of points[0], we see that: - * \f[ax+bz+c = 0.495 * 3.02 + (-1.927) * (-4.32) + (-2.906) = 6.91.\f] - * On the other hand, we have \f$y=6.89\f$. We see that the values - * \f$6.91\f$ and \f$6.89\f$ - * are near, so points[0] is very near the plane of equation \f$y=ax+bz+c\f$. - * - * Let's now describe precisely the parameters: - * @param numPoints the number of points - * @param points the array of pointers to the points on which to perform the linear regression - * @param result pointer to the vector in which to store the result. - This vector must be of the same type and size as the - data points. The meaning of its coords is as follows. - For brevity, let \f$n=Size\f$, - \f$r_i=result[i]\f$, - and \f$f=funcOfOthers\f$. Denote by - \f$x_0,\ldots,x_{n-1}\f$ - the n coordinates in the n-dimensional space. - Then the resulting equation is: - \f[ x_f = r_0 x_0 + \cdots + r_{f-1}x_{f-1} - + r_{f+1}x_{f+1} + \cdots + r_{n-1}x_{n-1} + r_n. \f] - * @param funcOfOthers Determines which coord to express as a function of the - others. Coords are numbered starting from 0, so that a - value of 0 means \f$x\f$, 1 means \f$y\f$, - 2 means \f$z\f$, ... - * - * \sa fitHyperplane() - */ -template -void linearRegression(int numPoints, - VectorType **points, - VectorType *result, - int funcOfOthers ) -{ - typedef typename VectorType::Scalar Scalar; - typedef Hyperplane HyperplaneType; - const int size = points[0]->size(); - result->resize(size); - HyperplaneType h(size); - fitHyperplane(numPoints, points, &h); - for(int i = 0; i < funcOfOthers; i++) - result->coeffRef(i) = - h.coeffs()[i] / h.coeffs()[funcOfOthers]; - for(int i = funcOfOthers; i < size; i++) - result->coeffRef(i) = - h.coeffs()[i+1] / h.coeffs()[funcOfOthers]; -} - -/** \ingroup LeastSquares_Module - * - * \leastsquares_module - * - * This function is quite similar to linearRegression(), so we refer to the - * documentation of this function and only list here the differences. - * - * The main difference from linearRegression() is that this function doesn't - * take a \a funcOfOthers argument. Instead, it finds a general equation - * of the form - * \f[ r_0 x_0 + \cdots + r_{n-1}x_{n-1} + r_n = 0, \f] - * where \f$n=Size\f$, \f$r_i=retCoefficients[i]\f$, and we denote by - * \f$x_0,\ldots,x_{n-1}\f$ the n coordinates in the n-dimensional space. - * - * Thus, the vector \a retCoefficients has size \f$n+1\f$, which is another - * difference from linearRegression(). - * - * In practice, this function performs an hyper-plane fit in a total least square sense - * via the following steps: - * 1 - center the data to the mean - * 2 - compute the covariance matrix - * 3 - pick the eigenvector corresponding to the smallest eigenvalue of the covariance matrix - * The ratio of the smallest eigenvalue and the second one gives us a hint about the relevance - * of the solution. This value is optionally returned in \a soundness. - * - * \sa linearRegression() - */ -template -void fitHyperplane(int numPoints, - VectorType **points, - HyperplaneType *result, - typename NumTraits::Real* soundness = 0) -{ - typedef typename VectorType::Scalar Scalar; - typedef Matrix CovMatrixType; - EIGEN_STATIC_ASSERT_VECTOR_ONLY(VectorType) - ei_assert(numPoints >= 1); - int size = points[0]->size(); - ei_assert(size+1 == result->coeffs().size()); - - // compute the mean of the data - VectorType mean = VectorType::Zero(size); - for(int i = 0; i < numPoints; ++i) - mean += *(points[i]); - mean /= numPoints; - - // compute the covariance matrix - CovMatrixType covMat = CovMatrixType::Zero(size, size); - for(int i = 0; i < numPoints; ++i) - { - VectorType diff = (*(points[i]) - mean).conjugate(); - covMat += diff * diff.adjoint(); - } - - // now we just have to pick the eigen vector with smallest eigen value - SelfAdjointEigenSolver eig(covMat); - result->normal() = eig.eigenvectors().col(0); - if (soundness) - *soundness = eig.eigenvalues().coeff(0)/eig.eigenvalues().coeff(1); - - // let's compute the constant coefficient such that the - // plane pass trough the mean point: - result->offset() = - (result->normal().cwise()* mean).sum(); -} - -} // end namespace Eigen - -#endif // EIGEN2_LEASTSQUARES_H diff --git a/splinter/src/Eigen2Support/Macros.h b/splinter/src/Eigen2Support/Macros.h deleted file mode 100644 index 351c32afb6..0000000000 --- a/splinter/src/Eigen2Support/Macros.h +++ /dev/null @@ -1,20 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2011 Benoit Jacob -// -// 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 - -#define ei_assert eigen_assert -#define ei_internal_assert eigen_internal_assert - -#define EIGEN_ALIGN_128 EIGEN_ALIGN16 - -#define EIGEN_ARCH_WANTS_ALIGNMENT EIGEN_ALIGN_STATICALLY - -#endif // EIGEN2_MACROS_H diff --git a/splinter/src/Eigen2Support/MathFunctions.h b/splinter/src/Eigen2Support/MathFunctions.h deleted file mode 100644 index 3544af2538..0000000000 --- a/splinter/src/Eigen2Support/MathFunctions.h +++ /dev/null @@ -1,57 +0,0 @@ -// 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 EIGEN2_MATH_FUNCTIONS_H -#define EIGEN2_MATH_FUNCTIONS_H - -namespace Eigen { - -template inline typename NumTraits::Real ei_real(const T& x) { return numext::real(x); } -template inline typename NumTraits::Real ei_imag(const T& x) { return numext::imag(x); } -template inline T ei_conj(const T& x) { return numext::conj(x); } -template inline typename NumTraits::Real ei_abs (const T& x) { using std::abs; return abs(x); } -template inline typename NumTraits::Real ei_abs2(const T& x) { return numext::abs2(x); } -template inline T ei_sqrt(const T& x) { using std::sqrt; return sqrt(x); } -template inline T ei_exp (const T& x) { using std::exp; return exp(x); } -template inline T ei_log (const T& x) { using std::log; return log(x); } -template inline T ei_sin (const T& x) { using std::sin; return sin(x); } -template inline T ei_cos (const T& x) { using std::cos; return cos(x); } -template inline T ei_atan2(const T& x,const T& y) { using std::atan2; return atan2(x,y); } -template inline T ei_pow (const T& x,const T& y) { return numext::pow(x,y); } -template inline T ei_random () { return internal::random(); } -template inline T ei_random (const T& x, const T& y) { return internal::random(x, y); } - -template inline T precision () { return NumTraits::dummy_precision(); } -template inline T machine_epsilon () { return NumTraits::epsilon(); } - - -template -inline bool ei_isMuchSmallerThan(const Scalar& x, const OtherScalar& y, - typename NumTraits::Real precision = NumTraits::dummy_precision()) -{ - return internal::isMuchSmallerThan(x, y, precision); -} - -template -inline bool ei_isApprox(const Scalar& x, const Scalar& y, - typename NumTraits::Real precision = NumTraits::dummy_precision()) -{ - return internal::isApprox(x, y, precision); -} - -template -inline bool ei_isApproxOrLessThan(const Scalar& x, const Scalar& y, - typename NumTraits::Real precision = NumTraits::dummy_precision()) -{ - return internal::isApproxOrLessThan(x, y, precision); -} - -} // end namespace Eigen - -#endif // EIGEN2_MATH_FUNCTIONS_H diff --git a/splinter/src/Eigen2Support/Memory.h b/splinter/src/Eigen2Support/Memory.h deleted file mode 100644 index f86372b6b5..0000000000 --- a/splinter/src/Eigen2Support/Memory.h +++ /dev/null @@ -1,45 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2011 Benoit Jacob -// -// 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); } -inline void* ei_handmade_aligned_malloc(size_t size) { return internal::handmade_aligned_malloc(size); } -inline void ei_handmade_aligned_free(void *ptr) { internal::handmade_aligned_free(ptr); } - -template inline void* ei_conditional_aligned_malloc(size_t size) -{ - return internal::conditional_aligned_malloc(size); -} -template inline void ei_conditional_aligned_free(void *ptr) -{ - internal::conditional_aligned_free(ptr); -} -template inline void* ei_conditional_aligned_realloc(void* ptr, size_t new_size, size_t old_size) -{ - return internal::conditional_aligned_realloc(ptr, new_size, old_size); -} - -template inline T* ei_aligned_new(size_t size) -{ - return internal::aligned_new(size); -} -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/splinter/src/Eigen2Support/Meta.h b/splinter/src/Eigen2Support/Meta.h deleted file mode 100644 index fa37cfc961..0000000000 --- a/splinter/src/Eigen2Support/Meta.h +++ /dev/null @@ -1,75 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2011 Benoit Jacob -// -// 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 -{}; - -struct ei_meta_true { enum { ret = 1 }; }; -struct ei_meta_false { enum { ret = 0 }; }; - -template -struct ei_meta_if { typedef Then ret; }; - -template -struct ei_meta_if { typedef Else ret; }; - -template struct ei_is_same_type { enum { ret = 0 }; }; -template struct ei_is_same_type { enum { ret = 1 }; }; - -template struct ei_unref { typedef T type; }; -template struct ei_unref { typedef T type; }; - -template struct ei_unpointer { typedef T type; }; -template struct ei_unpointer { typedef T type; }; -template struct ei_unpointer { typedef T type; }; - -template struct ei_unconst { typedef T type; }; -template struct ei_unconst { typedef T type; }; -template struct ei_unconst { typedef T & type; }; -template struct ei_unconst { typedef T * type; }; - -template struct ei_cleantype { typedef T type; }; -template struct ei_cleantype { typedef typename ei_cleantype::type type; }; -template struct ei_cleantype { typedef typename ei_cleantype::type type; }; -template struct ei_cleantype { typedef typename ei_cleantype::type type; }; -template struct ei_cleantype { typedef typename ei_cleantype::type type; }; -template struct ei_cleantype { typedef typename ei_cleantype::type type; }; - -/** \internal In short, it computes int(sqrt(\a Y)) with \a Y an integer. - * Usage example: \code ei_meta_sqrt<1023>::ret \endcode - */ -template Y))) > - // use ?: instead of || just to shut up a stupid gcc 4.3 warning -class ei_meta_sqrt -{ - enum { - MidX = (InfX+SupX)/2, - TakeInf = MidX*MidX > Y ? 1 : 0, - NewInf = int(TakeInf) ? InfX : int(MidX), - NewSup = int(TakeInf) ? int(MidX) : SupX - }; - public: - enum { ret = ei_meta_sqrt::ret }; -}; - -template -class ei_meta_sqrt { public: enum { ret = (SupX*SupX <= Y) ? SupX : InfX }; }; - -} // end namespace Eigen - -#endif // EIGEN2_META_H diff --git a/splinter/src/Eigen2Support/Minor.h b/splinter/src/Eigen2Support/Minor.h deleted file mode 100644 index 4cded5734f..0000000000 --- a/splinter/src/Eigen2Support/Minor.h +++ /dev/null @@ -1,117 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2009 Benoit Jacob -// -// 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 - * - * \brief Expression of a minor - * - * \param MatrixType the type of the object in which we are taking a minor - * - * This class represents an expression of a minor. It is the return - * type of MatrixBase::minor() and most of the time this is the only way it - * is used. - * - * \sa MatrixBase::minor() - */ - -namespace internal { -template -struct traits > - : traits -{ - typedef typename nested::type MatrixTypeNested; - typedef typename remove_reference::type _MatrixTypeNested; - typedef typename MatrixType::StorageKind StorageKind; - enum { - RowsAtCompileTime = (MatrixType::RowsAtCompileTime != Dynamic) ? - int(MatrixType::RowsAtCompileTime) - 1 : Dynamic, - ColsAtCompileTime = (MatrixType::ColsAtCompileTime != Dynamic) ? - int(MatrixType::ColsAtCompileTime) - 1 : Dynamic, - MaxRowsAtCompileTime = (MatrixType::MaxRowsAtCompileTime != Dynamic) ? - int(MatrixType::MaxRowsAtCompileTime) - 1 : Dynamic, - MaxColsAtCompileTime = (MatrixType::MaxColsAtCompileTime != Dynamic) ? - int(MatrixType::MaxColsAtCompileTime) - 1 : Dynamic, - Flags = _MatrixTypeNested::Flags & (HereditaryBits | LvalueBit), - CoeffReadCost = _MatrixTypeNested::CoeffReadCost // minor is used typically on tiny matrices, - // where loops are unrolled and the 'if' evaluates at compile time - }; -}; -} - -template class Minor - : public MatrixBase > -{ - public: - - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(Minor) - - inline Minor(const MatrixType& matrix, - Index row, Index col) - : m_matrix(matrix), m_row(row), m_col(col) - { - eigen_assert(row >= 0 && row < matrix.rows() - && col >= 0 && col < matrix.cols()); - } - - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Minor) - - inline Index rows() const { return m_matrix.rows() - 1; } - inline Index cols() const { return m_matrix.cols() - 1; } - - inline Scalar& coeffRef(Index row, Index col) - { - return m_matrix.const_cast_derived().coeffRef(row + (row >= m_row), col + (col >= m_col)); - } - - inline const Scalar coeff(Index row, Index col) const - { - return m_matrix.coeff(row + (row >= m_row), col + (col >= m_col)); - } - - protected: - const typename MatrixType::Nested m_matrix; - const Index m_row, m_col; -}; - -/** - * \return an expression of the (\a row, \a col)-minor of *this, - * i.e. an expression constructed from *this by removing the specified - * row and column. - * - * Example: \include MatrixBase_minor.cpp - * Output: \verbinclude MatrixBase_minor.out - * - * \sa class Minor - */ -template -inline Minor -MatrixBase::minor(Index row, Index col) -{ - return Minor(derived(), row, col); -} - -/** - * This is the const version of minor(). */ -template -inline const Minor -MatrixBase::minor(Index row, Index col) const -{ - return Minor(derived(), row, col); -} - -} // end namespace Eigen - -#endif // EIGEN_MINOR_H diff --git a/splinter/src/Eigen2Support/QR.h b/splinter/src/Eigen2Support/QR.h deleted file mode 100644 index 2042c98510..0000000000 --- a/splinter/src/Eigen2Support/QR.h +++ /dev/null @@ -1,67 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2011 Benoit Jacob -// -// 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 -{ - public: - - typedef HouseholderQR Base; - typedef Block MatrixRBlockType; - - QR() : Base() {} - - template - explicit QR(const T& t) : Base(t) {} - - template - bool solve(const MatrixBase& b, ResultType *result) const - { - *result = static_cast(this)->solve(b); - return true; - } - - MatrixType matrixQ(void) const { - MatrixType ret = MatrixType::Identity(this->rows(), this->cols()); - ret = this->householderQ() * ret; - return ret; - } - - bool isFullRank() const { - return true; - } - - const TriangularView - matrixR(void) const - { - int cols = this->cols(); - return MatrixRBlockType(this->matrixQR(), 0, 0, cols, cols).template triangularView(); - } -}; - -/** \return the QR decomposition of \c *this. - * - * \sa class QR - */ -template -const QR::PlainObject> -MatrixBase::qr() const -{ - return QR(eval()); -} - -} // end namespace Eigen - -#endif // EIGEN2_QR_H diff --git a/splinter/src/Eigen2Support/SVD.h b/splinter/src/Eigen2Support/SVD.h deleted file mode 100644 index 3d03d2288d..0000000000 --- a/splinter/src/Eigen2Support/SVD.h +++ /dev/null @@ -1,637 +0,0 @@ -// 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 EIGEN2_SVD_H -#define EIGEN2_SVD_H - -namespace Eigen { - -/** \ingroup SVD_Module - * \nonstableyet - * - * \class SVD - * - * \brief Standard SVD decomposition of a matrix and associated features - * - * \param MatrixType the type of the matrix of which we are computing the SVD decomposition - * - * This class performs a standard SVD decomposition of a real matrix A of size \c M x \c N - * with \c M \>= \c N. - * - * - * \sa MatrixBase::SVD() - */ -template class SVD -{ - private: - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - - enum { - PacketSize = internal::packet_traits::size, - AlignmentMask = int(PacketSize)-1, - MinSize = EIGEN_SIZE_MIN_PREFER_DYNAMIC(MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime) - }; - - typedef Matrix ColVector; - typedef Matrix RowVector; - - typedef Matrix MatrixUType; - typedef Matrix MatrixVType; - typedef Matrix SingularValuesType; - - public: - - SVD() {} // a user who relied on compiler-generated default compiler reported problems with MSVC in 2.0.7 - - SVD(const MatrixType& matrix) - : m_matU(matrix.rows(), (std::min)(matrix.rows(), matrix.cols())), - m_matV(matrix.cols(),matrix.cols()), - m_sigma((std::min)(matrix.rows(),matrix.cols())) - { - compute(matrix); - } - - template - bool solve(const MatrixBase &b, ResultType* result) const; - - const MatrixUType& matrixU() const { return m_matU; } - const SingularValuesType& singularValues() const { return m_sigma; } - const MatrixVType& matrixV() const { return m_matV; } - - void compute(const MatrixType& matrix); - SVD& sort(); - - template - void computeUnitaryPositive(UnitaryType *unitary, PositiveType *positive) const; - template - void computePositiveUnitary(PositiveType *positive, UnitaryType *unitary) const; - template - void computeRotationScaling(RotationType *unitary, ScalingType *positive) const; - template - void computeScalingRotation(ScalingType *positive, RotationType *unitary) const; - - protected: - /** \internal */ - MatrixUType m_matU; - /** \internal */ - MatrixVType m_matV; - /** \internal */ - SingularValuesType m_sigma; -}; - -/** Computes / recomputes the SVD decomposition A = U S V^* of \a matrix - * - * \note this code has been adapted from JAMA (public domain) - */ -template -void SVD::compute(const MatrixType& matrix) -{ - const int m = matrix.rows(); - const int n = matrix.cols(); - const int nu = (std::min)(m,n); - ei_assert(m>=n && "In Eigen 2.0, SVD only works for MxN matrices with M>=N. Sorry!"); - ei_assert(m>1 && "In Eigen 2.0, SVD doesn't work on 1x1 matrices"); - - m_matU.resize(m, nu); - m_matU.setZero(); - m_sigma.resize((std::min)(m,n)); - m_matV.resize(n,n); - - RowVector e(n); - ColVector work(m); - MatrixType matA(matrix); - const bool wantu = true; - const bool wantv = true; - int i=0, j=0, k=0; - - // Reduce A to bidiagonal form, storing the diagonal elements - // in s and the super-diagonal elements in e. - int nct = (std::min)(m-1,n); - int nrt = (std::max)(0,(std::min)(n-2,m)); - for (k = 0; k < (std::max)(nct,nrt); ++k) - { - if (k < nct) - { - // Compute the transformation for the k-th column and - // place the k-th diagonal in m_sigma[k]. - m_sigma[k] = matA.col(k).end(m-k).norm(); - if (m_sigma[k] != 0.0) // FIXME - { - if (matA(k,k) < 0.0) - m_sigma[k] = -m_sigma[k]; - matA.col(k).end(m-k) /= m_sigma[k]; - matA(k,k) += 1.0; - } - m_sigma[k] = -m_sigma[k]; - } - - for (j = k+1; j < n; ++j) - { - if ((k < nct) && (m_sigma[k] != 0.0)) - { - // Apply the transformation. - Scalar t = matA.col(k).end(m-k).eigen2_dot(matA.col(j).end(m-k)); // FIXME dot product or cwise prod + .sum() ?? - t = -t/matA(k,k); - matA.col(j).end(m-k) += t * matA.col(k).end(m-k); - } - - // Place the k-th row of A into e for the - // subsequent calculation of the row transformation. - e[j] = matA(k,j); - } - - // Place the transformation in U for subsequent back multiplication. - if (wantu & (k < nct)) - m_matU.col(k).end(m-k) = matA.col(k).end(m-k); - - if (k < nrt) - { - // Compute the k-th row transformation and place the - // k-th super-diagonal in e[k]. - e[k] = e.end(n-k-1).norm(); - if (e[k] != 0.0) - { - if (e[k+1] < 0.0) - e[k] = -e[k]; - e.end(n-k-1) /= e[k]; - e[k+1] += 1.0; - } - e[k] = -e[k]; - if ((k+1 < m) & (e[k] != 0.0)) - { - // Apply the transformation. - work.end(m-k-1) = matA.corner(BottomRight,m-k-1,n-k-1) * e.end(n-k-1); - for (j = k+1; j < n; ++j) - matA.col(j).end(m-k-1) += (-e[j]/e[k+1]) * work.end(m-k-1); - } - - // Place the transformation in V for subsequent back multiplication. - if (wantv) - m_matV.col(k).end(n-k-1) = e.end(n-k-1); - } - } - - - // Set up the final bidiagonal matrix or order p. - int p = (std::min)(n,m+1); - if (nct < n) - m_sigma[nct] = matA(nct,nct); - if (m < p) - m_sigma[p-1] = 0.0; - if (nrt+1 < p) - e[nrt] = matA(nrt,p-1); - e[p-1] = 0.0; - - // If required, generate U. - if (wantu) - { - for (j = nct; j < nu; ++j) - { - m_matU.col(j).setZero(); - m_matU(j,j) = 1.0; - } - for (k = nct-1; k >= 0; k--) - { - if (m_sigma[k] != 0.0) - { - for (j = k+1; j < nu; ++j) - { - Scalar t = m_matU.col(k).end(m-k).eigen2_dot(m_matU.col(j).end(m-k)); // FIXME is it really a dot product we want ? - t = -t/m_matU(k,k); - m_matU.col(j).end(m-k) += t * m_matU.col(k).end(m-k); - } - m_matU.col(k).end(m-k) = - m_matU.col(k).end(m-k); - m_matU(k,k) = Scalar(1) + m_matU(k,k); - if (k-1>0) - m_matU.col(k).start(k-1).setZero(); - } - else - { - m_matU.col(k).setZero(); - m_matU(k,k) = 1.0; - } - } - } - - // If required, generate V. - if (wantv) - { - for (k = n-1; k >= 0; k--) - { - if ((k < nrt) & (e[k] != 0.0)) - { - for (j = k+1; j < nu; ++j) - { - Scalar t = m_matV.col(k).end(n-k-1).eigen2_dot(m_matV.col(j).end(n-k-1)); // FIXME is it really a dot product we want ? - t = -t/m_matV(k+1,k); - m_matV.col(j).end(n-k-1) += t * m_matV.col(k).end(n-k-1); - } - } - m_matV.col(k).setZero(); - m_matV(k,k) = 1.0; - } - } - - // Main iteration loop for the singular values. - int pp = p-1; - int iter = 0; - Scalar eps = ei_pow(Scalar(2),ei_is_same_type::ret ? Scalar(-23) : Scalar(-52)); - while (p > 0) - { - int k=0; - int kase=0; - - // Here is where a test for too many iterations would go. - - // This section of the program inspects for - // negligible elements in the s and e arrays. On - // completion the variables kase and k are set as follows. - - // kase = 1 if s(p) and e[k-1] are negligible and k

= -1; --k) - { - if (k == -1) - break; - if (ei_abs(e[k]) <= eps*(ei_abs(m_sigma[k]) + ei_abs(m_sigma[k+1]))) - { - e[k] = 0.0; - break; - } - } - if (k == p-2) - { - kase = 4; - } - else - { - int ks; - for (ks = p-1; ks >= k; --ks) - { - if (ks == k) - break; - Scalar t = (ks != p ? ei_abs(e[ks]) : Scalar(0)) + (ks != k+1 ? ei_abs(e[ks-1]) : Scalar(0)); - if (ei_abs(m_sigma[ks]) <= eps*t) - { - m_sigma[ks] = 0.0; - break; - } - } - if (ks == k) - { - kase = 3; - } - else if (ks == p-1) - { - kase = 1; - } - else - { - kase = 2; - k = ks; - } - } - ++k; - - // Perform the task indicated by kase. - switch (kase) - { - - // Deflate negligible s(p). - case 1: - { - Scalar f(e[p-2]); - e[p-2] = 0.0; - for (j = p-2; j >= k; --j) - { - Scalar t(numext::hypot(m_sigma[j],f)); - Scalar cs(m_sigma[j]/t); - Scalar sn(f/t); - m_sigma[j] = t; - if (j != k) - { - f = -sn*e[j-1]; - e[j-1] = cs*e[j-1]; - } - if (wantv) - { - for (i = 0; i < n; ++i) - { - t = cs*m_matV(i,j) + sn*m_matV(i,p-1); - m_matV(i,p-1) = -sn*m_matV(i,j) + cs*m_matV(i,p-1); - m_matV(i,j) = t; - } - } - } - } - break; - - // Split at negligible s(k). - case 2: - { - Scalar f(e[k-1]); - e[k-1] = 0.0; - for (j = k; j < p; ++j) - { - Scalar t(numext::hypot(m_sigma[j],f)); - Scalar cs( m_sigma[j]/t); - Scalar sn(f/t); - m_sigma[j] = t; - f = -sn*e[j]; - e[j] = cs*e[j]; - if (wantu) - { - for (i = 0; i < m; ++i) - { - t = cs*m_matU(i,j) + sn*m_matU(i,k-1); - m_matU(i,k-1) = -sn*m_matU(i,j) + cs*m_matU(i,k-1); - m_matU(i,j) = t; - } - } - } - } - break; - - // Perform one qr step. - case 3: - { - // Calculate the shift. - Scalar scale = (std::max)((std::max)((std::max)((std::max)( - ei_abs(m_sigma[p-1]),ei_abs(m_sigma[p-2])),ei_abs(e[p-2])), - ei_abs(m_sigma[k])),ei_abs(e[k])); - Scalar sp = m_sigma[p-1]/scale; - Scalar spm1 = m_sigma[p-2]/scale; - Scalar epm1 = e[p-2]/scale; - Scalar sk = m_sigma[k]/scale; - Scalar ek = e[k]/scale; - Scalar b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/Scalar(2); - Scalar c = (sp*epm1)*(sp*epm1); - Scalar shift(0); - if ((b != 0.0) || (c != 0.0)) - { - shift = ei_sqrt(b*b + c); - if (b < 0.0) - shift = -shift; - shift = c/(b + shift); - } - Scalar f = (sk + sp)*(sk - sp) + shift; - Scalar g = sk*ek; - - // Chase zeros. - - for (j = k; j < p-1; ++j) - { - Scalar t = numext::hypot(f,g); - Scalar cs = f/t; - Scalar sn = g/t; - if (j != k) - e[j-1] = t; - f = cs*m_sigma[j] + sn*e[j]; - e[j] = cs*e[j] - sn*m_sigma[j]; - g = sn*m_sigma[j+1]; - m_sigma[j+1] = cs*m_sigma[j+1]; - if (wantv) - { - for (i = 0; i < n; ++i) - { - t = cs*m_matV(i,j) + sn*m_matV(i,j+1); - m_matV(i,j+1) = -sn*m_matV(i,j) + cs*m_matV(i,j+1); - m_matV(i,j) = t; - } - } - t = numext::hypot(f,g); - cs = f/t; - sn = g/t; - m_sigma[j] = t; - f = cs*e[j] + sn*m_sigma[j+1]; - m_sigma[j+1] = -sn*e[j] + cs*m_sigma[j+1]; - g = sn*e[j+1]; - e[j+1] = cs*e[j+1]; - if (wantu && (j < m-1)) - { - for (i = 0; i < m; ++i) - { - t = cs*m_matU(i,j) + sn*m_matU(i,j+1); - m_matU(i,j+1) = -sn*m_matU(i,j) + cs*m_matU(i,j+1); - m_matU(i,j) = t; - } - } - } - e[p-2] = f; - iter = iter + 1; - } - break; - - // Convergence. - case 4: - { - // Make the singular values positive. - if (m_sigma[k] <= 0.0) - { - m_sigma[k] = m_sigma[k] < Scalar(0) ? -m_sigma[k] : Scalar(0); - if (wantv) - m_matV.col(k).start(pp+1) = -m_matV.col(k).start(pp+1); - } - - // Order the singular values. - while (k < pp) - { - if (m_sigma[k] >= m_sigma[k+1]) - break; - Scalar t = m_sigma[k]; - m_sigma[k] = m_sigma[k+1]; - m_sigma[k+1] = t; - if (wantv && (k < n-1)) - m_matV.col(k).swap(m_matV.col(k+1)); - if (wantu && (k < m-1)) - m_matU.col(k).swap(m_matU.col(k+1)); - ++k; - } - iter = 0; - p--; - } - break; - } // end big switch - } // end iterations -} - -template -SVD& SVD::sort() -{ - int mu = m_matU.rows(); - int mv = m_matV.rows(); - int n = m_matU.cols(); - - for (int i=0; i p) - { - k = j; - p = m_sigma.coeff(j); - } - } - if (k != i) - { - m_sigma.coeffRef(k) = m_sigma.coeff(i); // i.e. - m_sigma.coeffRef(i) = p; // swaps the i-th and the k-th elements - - int j = mu; - for(int s=0; j!=0; ++s, --j) - std::swap(m_matU.coeffRef(s,i), m_matU.coeffRef(s,k)); - - j = mv; - for (int s=0; j!=0; ++s, --j) - std::swap(m_matV.coeffRef(s,i), m_matV.coeffRef(s,k)); - } - } - return *this; -} - -/** \returns the solution of \f$ A x = b \f$ using the current SVD decomposition of A. - * The parts of the solution corresponding to zero singular values are ignored. - * - * \sa MatrixBase::svd(), LU::solve(), LLT::solve() - */ -template -template -bool SVD::solve(const MatrixBase &b, ResultType* result) const -{ - ei_assert(b.rows() == m_matU.rows()); - - Scalar maxVal = m_sigma.cwise().abs().maxCoeff(); - for (int j=0; j aux = m_matU.transpose() * b.col(j); - - for (int i = 0; i col(j) = m_matV * aux; - } - return true; -} - -/** Computes the polar decomposition of the matrix, as a product unitary x positive. - * - * If either pointer is zero, the corresponding computation is skipped. - * - * Only for square matrices. - * - * \sa computePositiveUnitary(), computeRotationScaling() - */ -template -template -void SVD::computeUnitaryPositive(UnitaryType *unitary, - PositiveType *positive) const -{ - ei_assert(m_matU.cols() == m_matV.cols() && "Polar decomposition is only for square matrices"); - if(unitary) *unitary = m_matU * m_matV.adjoint(); - if(positive) *positive = m_matV * m_sigma.asDiagonal() * m_matV.adjoint(); -} - -/** Computes the polar decomposition of the matrix, as a product positive x unitary. - * - * If either pointer is zero, the corresponding computation is skipped. - * - * Only for square matrices. - * - * \sa computeUnitaryPositive(), computeRotationScaling() - */ -template -template -void SVD::computePositiveUnitary(UnitaryType *positive, - PositiveType *unitary) const -{ - ei_assert(m_matU.rows() == m_matV.rows() && "Polar decomposition is only for square matrices"); - if(unitary) *unitary = m_matU * m_matV.adjoint(); - if(positive) *positive = m_matU * m_sigma.asDiagonal() * m_matU.adjoint(); -} - -/** decomposes the matrix as a product rotation x scaling, the scaling being - * not necessarily positive. - * - * If either pointer is zero, the corresponding computation is skipped. - * - * This method requires the Geometry module. - * - * \sa computeScalingRotation(), computeUnitaryPositive() - */ -template -template -void SVD::computeRotationScaling(RotationType *rotation, ScalingType *scaling) const -{ - ei_assert(m_matU.rows() == m_matV.rows() && "Polar decomposition is only for square matrices"); - Scalar x = (m_matU * m_matV.adjoint()).determinant(); // so x has absolute value 1 - Matrix sv(m_sigma); - sv.coeffRef(0) *= x; - if(scaling) scaling->lazyAssign(m_matV * sv.asDiagonal() * m_matV.adjoint()); - if(rotation) - { - MatrixType m(m_matU); - m.col(0) /= x; - rotation->lazyAssign(m * m_matV.adjoint()); - } -} - -/** decomposes the matrix as a product scaling x rotation, the scaling being - * not necessarily positive. - * - * If either pointer is zero, the corresponding computation is skipped. - * - * This method requires the Geometry module. - * - * \sa computeRotationScaling(), computeUnitaryPositive() - */ -template -template -void SVD::computeScalingRotation(ScalingType *scaling, RotationType *rotation) const -{ - ei_assert(m_matU.rows() == m_matV.rows() && "Polar decomposition is only for square matrices"); - Scalar x = (m_matU * m_matV.adjoint()).determinant(); // so x has absolute value 1 - Matrix sv(m_sigma); - sv.coeffRef(0) *= x; - if(scaling) scaling->lazyAssign(m_matU * sv.asDiagonal() * m_matU.adjoint()); - if(rotation) - { - MatrixType m(m_matU); - m.col(0) /= x; - rotation->lazyAssign(m * m_matV.adjoint()); - } -} - - -/** \svd_module - * \returns the SVD decomposition of \c *this - */ -template -inline SVD::PlainObject> -MatrixBase::svd() const -{ - return SVD(derived()); -} - -} // end namespace Eigen - -#endif // EIGEN2_SVD_H diff --git a/splinter/src/Eigen2Support/TriangularSolver.h b/splinter/src/Eigen2Support/TriangularSolver.h deleted file mode 100644 index ebbeb3b495..0000000000 --- a/splinter/src/Eigen2Support/TriangularSolver.h +++ /dev/null @@ -1,42 +0,0 @@ -// 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_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; -const unsigned int LowerTriangularBit = Lower; - -const unsigned int UpperTriangular = Upper; -const unsigned int LowerTriangular = Lower; -const unsigned int UnitUpperTriangular = UnitUpper; -const unsigned int UnitLowerTriangular = UnitLower; - -template -template -typename ExpressionType::PlainObject -Flagged::solveTriangular(const MatrixBase& other) const -{ - return m_matrix.template triangularView().solve(other.derived()); -} - -template -template -void Flagged::solveTriangularInPlace(const MatrixBase& other) const -{ - m_matrix.template triangularView().solveInPlace(other.derived()); -} - -} // end namespace Eigen - -#endif // EIGEN_TRIANGULAR_SOLVER2_H diff --git a/splinter/src/Eigen2Support/VectorBlock.h b/splinter/src/Eigen2Support/VectorBlock.h deleted file mode 100644 index 71a8080a9f..0000000000 --- a/splinter/src/Eigen2Support/VectorBlock.h +++ /dev/null @@ -1,94 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// 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 -MatrixBase::start(Index size) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return VectorBlock(derived(), 0, size); -} - -/** \deprecated use DenseMase::head(Index) */ -template -inline const VectorBlock -MatrixBase::start(Index size) const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return VectorBlock(derived(), 0, size); -} - -/** \deprecated use DenseMase::tail(Index) */ -template -inline VectorBlock -MatrixBase::end(Index size) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return VectorBlock(derived(), this->size() - size, size); -} - -/** \deprecated use DenseMase::tail(Index) */ -template -inline const VectorBlock -MatrixBase::end(Index size) const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return VectorBlock(derived(), this->size() - size, size); -} - -/** \deprecated use DenseMase::head() */ -template -template -inline VectorBlock -MatrixBase::start() -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return VectorBlock(derived(), 0); -} - -/** \deprecated use DenseMase::head() */ -template -template -inline const VectorBlock -MatrixBase::start() const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return VectorBlock(derived(), 0); -} - -/** \deprecated use DenseMase::tail() */ -template -template -inline VectorBlock -MatrixBase::end() -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return VectorBlock(derived(), size() - Size); -} - -/** \deprecated use DenseMase::tail() */ -template -template -inline const VectorBlock -MatrixBase::end() const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return VectorBlock(derived(), size() - Size); -} - -} // end namespace Eigen - -#endif // EIGEN2_VECTORBLOCK_H diff --git a/splinter/src/Geometry/Homogeneous.h b/splinter/src/Geometry/Homogeneous.h deleted file mode 100644 index 372e422b92..0000000000 --- a/splinter/src/Geometry/Homogeneous.h +++ /dev/null @@ -1,307 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009-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_HOMOGENEOUS_H -#define EIGEN_HOMOGENEOUS_H - -namespace Eigen { - -/** \geometry_module \ingroup Geometry_Module - * - * \class Homogeneous - * - * \brief Expression of one (or a set of) homogeneous vector(s) - * - * \param MatrixType the type of the object in which we are making homogeneous - * - * This class represents an expression of one (or a set of) homogeneous vector(s). - * It is the return type of MatrixBase::homogeneous() and most of the time - * this is the only way it is used. - * - * \sa MatrixBase::homogeneous() - */ - -namespace internal { - -template -struct traits > - : traits -{ - typedef typename traits::StorageKind StorageKind; - typedef typename nested::type MatrixTypeNested; - typedef typename remove_reference::type _MatrixTypeNested; - enum { - RowsPlusOne = (MatrixType::RowsAtCompileTime != Dynamic) ? - int(MatrixType::RowsAtCompileTime) + 1 : Dynamic, - ColsPlusOne = (MatrixType::ColsAtCompileTime != Dynamic) ? - int(MatrixType::ColsAtCompileTime) + 1 : Dynamic, - RowsAtCompileTime = Direction==Vertical ? RowsPlusOne : MatrixType::RowsAtCompileTime, - ColsAtCompileTime = Direction==Horizontal ? ColsPlusOne : MatrixType::ColsAtCompileTime, - MaxRowsAtCompileTime = RowsAtCompileTime, - MaxColsAtCompileTime = ColsAtCompileTime, - TmpFlags = _MatrixTypeNested::Flags & HereditaryBits, - Flags = ColsAtCompileTime==1 ? (TmpFlags & ~RowMajorBit) - : RowsAtCompileTime==1 ? (TmpFlags | RowMajorBit) - : TmpFlags, - CoeffReadCost = _MatrixTypeNested::CoeffReadCost - }; -}; - -template struct homogeneous_left_product_impl; -template struct homogeneous_right_product_impl; - -} // end namespace internal - -template class Homogeneous - : internal::no_assignment_operator, public MatrixBase > -{ - public: - - enum { Direction = _Direction }; - - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(Homogeneous) - - inline Homogeneous(const MatrixType& matrix) - : m_matrix(matrix) - {} - - inline Index rows() const { return m_matrix.rows() + (int(Direction)==Vertical ? 1 : 0); } - inline Index cols() const { return m_matrix.cols() + (int(Direction)==Horizontal ? 1 : 0); } - - inline Scalar coeff(Index row, Index col) const - { - if( (int(Direction)==Vertical && row==m_matrix.rows()) - || (int(Direction)==Horizontal && col==m_matrix.cols())) - return Scalar(1); - return m_matrix.coeff(row, col); - } - - template - inline const internal::homogeneous_right_product_impl - operator* (const MatrixBase& rhs) const - { - eigen_assert(int(Direction)==Horizontal); - return internal::homogeneous_right_product_impl(m_matrix,rhs.derived()); - } - - template friend - inline const internal::homogeneous_left_product_impl - operator* (const MatrixBase& lhs, const Homogeneous& rhs) - { - eigen_assert(int(Direction)==Vertical); - return internal::homogeneous_left_product_impl(lhs.derived(),rhs.m_matrix); - } - - template friend - inline const internal::homogeneous_left_product_impl > - operator* (const Transform& lhs, const Homogeneous& rhs) - { - eigen_assert(int(Direction)==Vertical); - return internal::homogeneous_left_product_impl >(lhs,rhs.m_matrix); - } - - protected: - typename MatrixType::Nested m_matrix; -}; - -/** \geometry_module - * - * \return an expression of the equivalent homogeneous vector - * - * \only_for_vectors - * - * Example: \include MatrixBase_homogeneous.cpp - * Output: \verbinclude MatrixBase_homogeneous.out - * - * \sa class Homogeneous - */ -template -inline typename MatrixBase::HomogeneousReturnType -MatrixBase::homogeneous() const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived); - return derived(); -} - -/** \geometry_module - * - * \returns a matrix expression of homogeneous column (or row) vectors - * - * Example: \include VectorwiseOp_homogeneous.cpp - * Output: \verbinclude VectorwiseOp_homogeneous.out - * - * \sa MatrixBase::homogeneous() */ -template -inline Homogeneous -VectorwiseOp::homogeneous() const -{ - return _expression(); -} - -/** \geometry_module - * - * \returns an expression of the homogeneous normalized vector of \c *this - * - * Example: \include MatrixBase_hnormalized.cpp - * Output: \verbinclude MatrixBase_hnormalized.out - * - * \sa VectorwiseOp::hnormalized() */ -template -inline const typename MatrixBase::HNormalizedReturnType -MatrixBase::hnormalized() const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived); - return ConstStartMinusOne(derived(),0,0, - ColsAtCompileTime==1?size()-1:1, - ColsAtCompileTime==1?1:size()-1) / coeff(size()-1); -} - -/** \geometry_module - * - * \returns an expression of the homogeneous normalized vector of \c *this - * - * Example: \include DirectionWise_hnormalized.cpp - * Output: \verbinclude DirectionWise_hnormalized.out - * - * \sa MatrixBase::hnormalized() */ -template -inline const typename VectorwiseOp::HNormalizedReturnType -VectorwiseOp::hnormalized() const -{ - return HNormalized_Block(_expression(),0,0, - Direction==Vertical ? _expression().rows()-1 : _expression().rows(), - Direction==Horizontal ? _expression().cols()-1 : _expression().cols()).cwiseQuotient( - Replicate - (HNormalized_Factors(_expression(), - Direction==Vertical ? _expression().rows()-1:0, - Direction==Horizontal ? _expression().cols()-1:0, - Direction==Vertical ? 1 : _expression().rows(), - Direction==Horizontal ? 1 : _expression().cols()), - Direction==Vertical ? _expression().rows()-1 : 1, - Direction==Horizontal ? _expression().cols()-1 : 1)); -} - -namespace internal { - -template -struct take_matrix_for_product -{ - typedef MatrixOrTransformType type; - static const type& run(const type &x) { return x; } -}; - -template -struct take_matrix_for_product > -{ - typedef Transform TransformType; - typedef typename internal::add_const::type type; - static type run (const TransformType& x) { return x.affine(); } -}; - -template -struct take_matrix_for_product > -{ - typedef Transform TransformType; - typedef typename TransformType::MatrixType type; - static const type& run (const TransformType& x) { return x.matrix(); } -}; - -template -struct traits,Lhs> > -{ - typedef typename take_matrix_for_product::type LhsMatrixType; - typedef typename remove_all::type MatrixTypeCleaned; - typedef typename remove_all::type LhsMatrixTypeCleaned; - typedef typename make_proper_matrix_type< - typename traits::Scalar, - LhsMatrixTypeCleaned::RowsAtCompileTime, - MatrixTypeCleaned::ColsAtCompileTime, - MatrixTypeCleaned::PlainObject::Options, - LhsMatrixTypeCleaned::MaxRowsAtCompileTime, - MatrixTypeCleaned::MaxColsAtCompileTime>::type ReturnType; -}; - -template -struct homogeneous_left_product_impl,Lhs> - : public ReturnByValue,Lhs> > -{ - typedef typename traits::LhsMatrixType LhsMatrixType; - typedef typename remove_all::type LhsMatrixTypeCleaned; - typedef typename remove_all::type LhsMatrixTypeNested; - typedef typename MatrixType::Index Index; - homogeneous_left_product_impl(const Lhs& lhs, const MatrixType& rhs) - : m_lhs(take_matrix_for_product::run(lhs)), - m_rhs(rhs) - {} - - inline Index rows() const { return m_lhs.rows(); } - inline Index cols() const { return m_rhs.cols(); } - - template void evalTo(Dest& dst) const - { - // FIXME investigate how to allow lazy evaluation of this product when possible - dst = Block - (m_lhs,0,0,m_lhs.rows(),m_lhs.cols()-1) * m_rhs; - dst += m_lhs.col(m_lhs.cols()-1).rowwise() - .template replicate(m_rhs.cols()); - } - - typename LhsMatrixTypeCleaned::Nested m_lhs; - typename MatrixType::Nested m_rhs; -}; - -template -struct traits,Rhs> > -{ - typedef typename make_proper_matrix_type::Scalar, - MatrixType::RowsAtCompileTime, - Rhs::ColsAtCompileTime, - MatrixType::PlainObject::Options, - MatrixType::MaxRowsAtCompileTime, - Rhs::MaxColsAtCompileTime>::type ReturnType; -}; - -template -struct homogeneous_right_product_impl,Rhs> - : public ReturnByValue,Rhs> > -{ - typedef typename remove_all::type RhsNested; - typedef typename MatrixType::Index Index; - homogeneous_right_product_impl(const MatrixType& lhs, const Rhs& rhs) - : m_lhs(lhs), m_rhs(rhs) - {} - - inline Index rows() const { return m_lhs.rows(); } - inline Index cols() const { return m_rhs.cols(); } - - template void evalTo(Dest& dst) const - { - // FIXME investigate how to allow lazy evaluation of this product when possible - dst = m_lhs * Block - (m_rhs,0,0,m_rhs.rows()-1,m_rhs.cols()); - dst += m_rhs.row(m_rhs.rows()-1).colwise() - .template replicate(m_lhs.rows()); - } - - typename MatrixType::Nested m_lhs; - typename Rhs::Nested m_rhs; -}; - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_HOMOGENEOUS_H diff --git a/splinter/src/Householder/BlockHouseholder.h b/splinter/src/Householder/BlockHouseholder.h deleted file mode 100644 index 60dbea5f56..0000000000 --- a/splinter/src/Householder/BlockHouseholder.h +++ /dev/null @@ -1,68 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2010 Vincent Lejeune -// 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_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 */ -template -void make_block_householder_triangular_factor(TriangularFactorType& triFactor, const VectorsType& vectors, const CoeffsType& hCoeffs) -{ - typedef typename TriangularFactorType::Index Index; - typedef typename VectorsType::Scalar Scalar; - const Index nbVecs = vectors.cols(); - eigen_assert(triFactor.rows() == nbVecs && triFactor.cols() == nbVecs && vectors.rows()>=nbVecs); - - for(Index i = 0; i < nbVecs; i++) - { - Index rs = vectors.rows() - i; - Scalar Vii = vectors(i,i); - vectors.const_cast_derived().coeffRef(i,i) = Scalar(1); - triFactor.col(i).head(i).noalias() = -hCoeffs(i) * vectors.block(i, 0, rs, i).adjoint() - * vectors.col(i).tail(rs); - vectors.const_cast_derived().coeffRef(i, i) = Vii; - // FIXME add .noalias() once the triangular product can work inplace - triFactor.col(i).head(i) = triFactor.block(0,0,i,i).template triangularView() - * triFactor.col(i).head(i); - triFactor(i,i) = hCoeffs(i); - } -} - -/** \internal */ -template -void apply_block_householder_on_the_left(MatrixType& mat, const VectorsType& vectors, const CoeffsType& hCoeffs) -{ - typedef typename MatrixType::Index Index; - enum { TFactorSize = MatrixType::ColsAtCompileTime }; - Index nbVecs = vectors.cols(); - Matrix T(nbVecs,nbVecs); - make_block_householder_triangular_factor(T, vectors, hCoeffs); - - const TriangularView& V(vectors); - - // A -= V T V^* A - Matrix tmp = V.adjoint() * mat; - // FIXME add .noalias() once the triangular product can work inplace - tmp = T.template triangularView().adjoint() * tmp; - mat.noalias() -= V * tmp; -} - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_BLOCK_HOUSEHOLDER_H diff --git a/splinter/src/IterativeLinearSolvers/IterativeSolverBase.h b/splinter/src/IterativeLinearSolvers/IterativeSolverBase.h deleted file mode 100644 index 501ef2f8d8..0000000000 --- a/splinter/src/IterativeLinearSolvers/IterativeSolverBase.h +++ /dev/null @@ -1,282 +0,0 @@ -// 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. - */ - template - IterativeSolverBase(const EigenBase& A) - { - init(); - compute(A.derived()); - } - - ~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. - */ - template - Derived& analyzePattern(const EigenBase& A) - { - grabInput(A.derived()); - m_preconditioner.analyzePattern(*mp_matrix); - 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. - */ - template - Derived& factorize(const EigenBase& A) - { - grabInput(A.derived()); - eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); - m_preconditioner.factorize(*mp_matrix); - 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. - */ - template - Derived& compute(const EigenBase& A) - { - grabInput(A.derived()); - m_preconditioner.compute(*mp_matrix); - 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(const 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 - void grabInput(const EigenBase& A) - { - // we const cast to prevent the creation of a MatrixType temporary by the compiler. - grabInput_impl(A.const_cast_derived()); - } - - template - void grabInput_impl(const EigenBase& A) - { - m_copyMatrix = A; - mp_matrix = &m_copyMatrix; - } - - void grabInput_impl(MatrixType& A) - { - if(MatrixType::RowsAtCompileTime==Dynamic && MatrixType::ColsAtCompileTime==Dynamic) - m_copyMatrix.resize(0,0); - mp_matrix = &A; - } - - void init() - { - m_isInitialized = false; - m_analysisIsOk = false; - m_factorizationIsOk = false; - m_maxIterations = -1; - m_tolerance = NumTraits::epsilon(); - } - MatrixType m_copyMatrix; - 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/splinter/src/SVD/JacobiSVD.h b/splinter/src/SVD/JacobiSVD.h deleted file mode 100644 index 89ace381e1..0000000000 --- a/splinter/src/SVD/JacobiSVD.h +++ /dev/null @@ -1,976 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009-2010 Benoit Jacob -// -// 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 -template::IsComplex> -struct svd_precondition_2x2_block_to_be_real {}; - -/*** QR preconditioners (R-SVD) - *** - *** Their role is to reduce the problem of computing the SVD to the case of a square matrix. - *** This approach, known as R-SVD, is an optimization for rectangular-enough matrices, and is a requirement for - *** JacobiSVD which by itself is only able to work on square matrices. - ***/ - -enum { PreconditionIfMoreColsThanRows, PreconditionIfMoreRowsThanCols }; - -template -struct qr_preconditioner_should_do_anything -{ - enum { a = MatrixType::RowsAtCompileTime != Dynamic && - MatrixType::ColsAtCompileTime != Dynamic && - MatrixType::ColsAtCompileTime <= MatrixType::RowsAtCompileTime, - b = MatrixType::RowsAtCompileTime != Dynamic && - MatrixType::ColsAtCompileTime != Dynamic && - MatrixType::RowsAtCompileTime <= MatrixType::ColsAtCompileTime, - ret = !( (QRPreconditioner == NoQRPreconditioner) || - (Case == PreconditionIfMoreColsThanRows && bool(a)) || - (Case == PreconditionIfMoreRowsThanCols && bool(b)) ) - }; -}; - -template::ret -> struct qr_preconditioner_impl {}; - -template -class qr_preconditioner_impl -{ -public: - typedef typename MatrixType::Index Index; - void allocate(const JacobiSVD&) {} - bool run(JacobiSVD&, const MatrixType&) - { - return false; - } -}; - -/*** preconditioner using FullPivHouseholderQR ***/ - -template -class qr_preconditioner_impl -{ -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.~QRType(); - ::new (&m_qr) QRType(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()) - { - 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: - typedef FullPivHouseholderQR QRType; - QRType m_qr; - WorkspaceType m_workspace; -}; - -template -class qr_preconditioner_impl -{ -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.~QRType(); - ::new (&m_qr) QRType(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()) - { - 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: - typedef FullPivHouseholderQR QRType; - QRType m_qr; - TransposeTypeWithSameStorageOrder m_adjoint; - typename internal::plain_row_type::type m_workspace; -}; - -/*** preconditioner using ColPivHouseholderQR ***/ - -template -class qr_preconditioner_impl -{ -public: - typedef typename MatrixType::Index Index; - - void allocate(const JacobiSVD& svd) - { - if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols()) - { - m_qr.~QRType(); - ::new (&m_qr) QRType(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()) - { - 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()); - m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixU, m_workspace); - } - if(svd.computeV()) svd.m_matrixV = m_qr.colsPermutation(); - return true; - } - return false; - } - -private: - typedef ColPivHouseholderQR QRType; - QRType m_qr; - typename internal::plain_col_type::type m_workspace; -}; - -template -class qr_preconditioner_impl -{ -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.~QRType(); - ::new (&m_qr) QRType(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()) - { - 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()); - m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixV, m_workspace); - } - if(svd.computeU()) svd.m_matrixU = m_qr.colsPermutation(); - return true; - } - else return false; - } - -private: - typedef ColPivHouseholderQR QRType; - QRType m_qr; - TransposeTypeWithSameStorageOrder m_adjoint; - typename internal::plain_row_type::type m_workspace; -}; - -/*** preconditioner using HouseholderQR ***/ - -template -class qr_preconditioner_impl -{ -public: - typedef typename MatrixType::Index Index; - - void allocate(const JacobiSVD& svd) - { - if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols()) - { - m_qr.~QRType(); - ::new (&m_qr) QRType(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()) - { - 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()); - 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: - typedef HouseholderQR QRType; - QRType m_qr; - typename internal::plain_col_type::type m_workspace; -}; - -template -class qr_preconditioner_impl -{ -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.~QRType(); - ::new (&m_qr) QRType(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()) - { - 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()); - 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: - typedef HouseholderQR QRType; - QRType m_qr; - TransposeTypeWithSameStorageOrder m_adjoint; - typename internal::plain_row_type::type m_workspace; -}; - -/*** 2x2 SVD implementation - *** - *** JacobiSVD consists in performing a series of 2x2 SVD subproblems - ***/ - -template -struct svd_precondition_2x2_block_to_be_real -{ - typedef JacobiSVD SVD; - typedef typename SVD::Index Index; - static void run(typename SVD::WorkMatrixType&, SVD&, Index, Index) {} -}; - -template -struct svd_precondition_2x2_block_to_be_real -{ - typedef JacobiSVD SVD; - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::RealScalar RealScalar; - typedef typename SVD::Index Index; - static void run(typename SVD::WorkMatrixType& work_matrix, SVD& svd, Index p, Index q) - { - using std::sqrt; - Scalar z; - JacobiRotation rot; - RealScalar n = sqrt(numext::abs2(work_matrix.coeff(p,p)) + numext::abs2(work_matrix.coeff(q,p))); - - if(n==0) - { - z = abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q); - work_matrix.row(p) *= z; - if(svd.computeU()) svd.m_matrixU.col(p) *= conj(z); - if(work_matrix.coeff(q,q)!=Scalar(0)) - { - z = abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q); - work_matrix.row(q) *= z; - if(svd.computeU()) svd.m_matrixU.col(q) *= conj(z); - } - // otherwise the second row is already zero, so we have nothing to do. - } - else - { - rot.c() = conj(work_matrix.coeff(p,p)) / n; - rot.s() = work_matrix.coeff(q,p) / n; - work_matrix.applyOnTheLeft(p,q,rot); - if(svd.computeU()) svd.m_matrixU.applyOnTheRight(p,q,rot.adjoint()); - if(work_matrix.coeff(p,q) != Scalar(0)) - { - Scalar z = abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q); - work_matrix.col(q) *= z; - if(svd.computeV()) svd.m_matrixV.col(q) *= z; - } - if(work_matrix.coeff(q,q) != Scalar(0)) - { - z = abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q); - work_matrix.row(q) *= z; - if(svd.computeU()) svd.m_matrixU.col(q) *= conj(z); - } - } - } -}; - -template -void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q, - JacobiRotation *j_left, - JacobiRotation *j_right) -{ - using std::sqrt; - using std::abs; - Matrix m; - m << numext::real(matrix.coeff(p,p)), numext::real(matrix.coeff(p,q)), - numext::real(matrix.coeff(q,p)), numext::real(matrix.coeff(q,q)); - JacobiRotation rot1; - RealScalar t = m.coeff(0,0) + m.coeff(1,1); - RealScalar d = m.coeff(1,0) - m.coeff(0,1); - if(t == RealScalar(0)) - { - rot1.c() = RealScalar(0); - rot1.s() = d > RealScalar(0) ? RealScalar(1) : RealScalar(-1); - } - else - { - RealScalar t2d2 = numext::hypot(t,d); - rot1.c() = abs(t)/t2d2; - rot1.s() = d/t2d2; - if(tmakeJacobi(m,0,1); - *j_left = rot1 * j_right->transpose(); -} - -} // end namespace internal - -/** \ingroup SVD_Module - * - * - * \class JacobiSVD - * - * \brief Two-sided Jacobi SVD decomposition of a rectangular matrix - * - * \param MatrixType the type of the matrix of which we are computing the SVD decomposition - * \param QRPreconditioner this optional parameter allows to specify the type of QR decomposition that will be used internally - * for the R-SVD step for non-square matrices. See discussion of possible values below. - * - * SVD decomposition consists in decomposing any n-by-p matrix \a A as a product - * \f[ A = U S V^* \f] - * where \a U is a n-by-n unitary, \a V is a p-by-p unitary, and \a S is a n-by-p real positive matrix which is zero outside of its main diagonal; - * the diagonal entries of S are known as the \em singular \em values of \a A and the columns of \a U and \a V are known as the left - * and right \em singular \em vectors of \a A respectively. - * - * Singular values are always sorted in decreasing order. - * - * This JacobiSVD decomposition computes only the singular values by default. If you want \a U or \a V, you need to ask for them explicitly. - * - * You can ask for only \em thin \a U or \a V to be computed, meaning the following. In case of a rectangular n-by-p matrix, letting \a m be the - * smaller value among \a n and \a p, there are only \a m singular vectors; the remaining columns of \a U and \a V do not correspond to actual - * singular vectors. Asking for \em thin \a U or \a V means asking for only their \a m first columns to be formed. So \a U is then a n-by-m matrix, - * and \a V is then a p-by-m matrix. Notice that thin \a U and \a V are all you need for (least squares) solving. - * - * 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. - * In particular, like any R-SVD, it takes advantage of non-squareness in that its complexity is only linear in the greater dimension. - * - * 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. - * Contrary to other QRs, it doesn't allow computing thin unitaries. - * \li HouseholderQRPreconditioner is the fastest, and less safe and accurate than the pivoting variants. It uses non-pivoting QR. - * This is very similar in safety and accuracy to the bidiagonalization process used by bidiagonalizing SVD algorithms (since bidiagonalization - * is inherently non-pivoting). However the resulting SVD is still more reliable than bidiagonalizing SVDs because the Jacobi-based iterarive - * process is more reliable than the optimized bidiagonal SVD iterations. - * \li NoQRPreconditioner allows not to use a QR preconditioner at all. This is useful if you know that you will only be computing - * JacobiSVD decompositions of square matrices. Non-square matrices require a QR preconditioner. Using this option will result in - * faster compilation and smaller executable code. It won't significantly speed up computation, since JacobiSVD is always checking - * if QR preconditioning is needed before applying it anyway. - * - * \sa MatrixBase::jacobiSvd() - */ -template class JacobiSVD -{ - public: - - typedef _MatrixType MatrixType; - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef typename MatrixType::Index Index; - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime, - DiagSizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime,ColsAtCompileTime), - MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - MaxDiagSizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED(MaxRowsAtCompileTime,MaxColsAtCompileTime), - MatrixOptions = MatrixType::Options - }; - - typedef Matrix - MatrixUType; - typedef Matrix - MatrixVType; - typedef typename internal::plain_diag_type::type SingularValuesType; - typedef typename internal::plain_row_type::type RowType; - typedef typename internal::plain_col_type::type ColType; - typedef Matrix - WorkMatrixType; - - /** \brief Default Constructor. - * - * The default constructor is useful in cases in which the user intends to - * perform decompositions via JacobiSVD::compute(const MatrixType&). - */ - JacobiSVD() - : m_isInitialized(false), - m_isAllocated(false), - m_usePrescribedThreshold(false), - m_computationOptions(0), - m_rows(-1), m_cols(-1), m_diagSize(0) - {} - - - /** \brief Default Constructor with memory preallocation - * - * Like the default constructor but with preallocation of the internal data - * according to the specified problem size. - * \sa JacobiSVD() - */ - JacobiSVD(Index rows, Index cols, unsigned int computationOptions = 0) - : m_isInitialized(false), - m_isAllocated(false), - m_usePrescribedThreshold(false), - m_computationOptions(0), - m_rows(-1), m_cols(-1) - { - allocate(rows, cols, computationOptions); - } - - /** \brief Constructor performing the decomposition of given matrix. - * - * \param matrix the matrix to decompose - * \param computationOptions optional parameter allowing to specify if you want full or thin U or V unitaries to be computed. - * By default, none is computed. This is a bit-field, the possible bits are #ComputeFullU, #ComputeThinU, - * #ComputeFullV, #ComputeThinV. - * - * Thin unitaries are only available if your matrix type has a Dynamic number of columns (for example MatrixXf). They also are not - * available with the (non-default) FullPivHouseholderQR preconditioner. - */ - JacobiSVD(const MatrixType& matrix, unsigned int computationOptions = 0) - : m_isInitialized(false), - m_isAllocated(false), - m_usePrescribedThreshold(false), - m_computationOptions(0), - m_rows(-1), m_cols(-1) - { - compute(matrix, computationOptions); - } - - /** \brief Method performing the decomposition of given matrix using custom options. - * - * \param matrix the matrix to decompose - * \param computationOptions optional parameter allowing to specify if you want full or thin U or V unitaries to be computed. - * By default, none is computed. This is a bit-field, the possible bits are #ComputeFullU, #ComputeThinU, - * #ComputeFullV, #ComputeThinV. - * - * Thin unitaries are only available if your matrix type has a Dynamic number of columns (for example MatrixXf). They also are not - * available with the (non-default) FullPivHouseholderQR preconditioner. - */ - JacobiSVD& compute(const MatrixType& matrix, unsigned int computationOptions); - - /** \brief Method performing the decomposition of given matrix using current options. - * - * \param matrix the matrix to decompose - * - * This method uses the current \a computationOptions, as already passed to the constructor or to compute(const MatrixType&, unsigned int). - */ - JacobiSVD& compute(const MatrixType& matrix) - { - return compute(matrix, m_computationOptions); - } - - /** \returns the \a U matrix. - * - * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, - * the U matrix is n-by-n if you asked for #ComputeFullU, and is n-by-m if you asked for #ComputeThinU. - * - * The \a m first columns of \a U are the left singular vectors of the matrix being decomposed. - * - * This method asserts that you asked for \a U to be computed. - */ - const MatrixUType& matrixU() const - { - eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); - eigen_assert(computeU() && "This JacobiSVD decomposition didn't compute U. Did you ask for it?"); - return m_matrixU; - } - - /** \returns the \a V matrix. - * - * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, - * the V matrix is p-by-p if you asked for #ComputeFullV, and is p-by-m if you asked for ComputeThinV. - * - * The \a m first columns of \a V are the right singular vectors of the matrix being decomposed. - * - * This method asserts that you asked for \a V to be computed. - */ - const MatrixVType& matrixV() const - { - eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); - eigen_assert(computeV() && "This JacobiSVD decomposition didn't compute V. Did you ask for it?"); - return m_matrixV; - } - - /** \returns the vector of singular values. - * - * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, the - * returned vector has size \a m. Singular values are always sorted in decreasing order. - */ - const SingularValuesType& singularValues() const - { - eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); - return m_singularValues; - } - - /** \returns true if \a U (full or thin) is asked for in this SVD decomposition */ - inline bool computeU() const { return m_computeFullU || m_computeThinU; } - /** \returns true if \a V (full or thin) is asked for in this SVD decomposition */ - inline bool computeV() const { return m_computeFullV || m_computeThinV; } - - /** \returns a (least squares) solution of \f$ A x = b \f$ using the current SVD decomposition of A. - * - * \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$. - */ - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); - eigen_assert(computeU() && computeV() && "JacobiSVD::solve() requires both unitaries U and V to be computed (thin unitaries suffice)."); - return internal::solve_retval(*this, b.derived()); - } - - /** \returns the number of singular values that are not exactly 0 */ - Index nonzeroSingularValues() const - { - eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); - return m_nonzeroSingularValues; - } - - /** \returns the rank of the matrix of which \c *this is the SVD. - * - * \note This method has to determine which singular values should be considered nonzero. - * For that, it uses the threshold value that you can control by calling - * setThreshold(const RealScalar&). - */ - inline Index rank() const - { - using std::abs; - eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); - if(m_singularValues.size()==0) return 0; - RealScalar premultiplied_threshold = m_singularValues.coeff(0) * threshold(); - Index i = m_nonzeroSingularValues-1; - while(i>=0 && m_singularValues.coeff(i) < premultiplied_threshold) --i; - return i+1; - } - - /** Allows to prescribe a threshold to be used by certain methods, such as rank() and solve(), - * which need to determine when singular values are to be considered nonzero. - * This is not used for the SVD decomposition itself. - * - * When it needs to get the threshold value, Eigen calls threshold(). - * The default is \c NumTraits::epsilon() - * - * \param threshold The new value to use as the threshold. - * - * A singular value will be considered nonzero if its value is strictly greater than - * \f$ \vert singular value \vert \leqslant threshold \times \vert max singular value \vert \f$. - * - * If you want to come back to the default behavior, call setThreshold(Default_t) - */ - JacobiSVD& setThreshold(const RealScalar& threshold) - { - m_usePrescribedThreshold = true; - m_prescribedThreshold = threshold; - return *this; - } - - /** Allows to come back to the default behavior, letting Eigen use its default formula for - * determining the threshold. - * - * You should pass the special object Eigen::Default as parameter here. - * \code svd.setThreshold(Eigen::Default); \endcode - * - * See the documentation of setThreshold(const RealScalar&). - */ - JacobiSVD& setThreshold(Default_t) - { - m_usePrescribedThreshold = false; - return *this; - } - - /** Returns the threshold that will be used by certain methods such as rank(). - * - * See the documentation of setThreshold(const RealScalar&). - */ - RealScalar threshold() const - { - eigen_assert(m_isInitialized || m_usePrescribedThreshold); - return m_usePrescribedThreshold ? m_prescribedThreshold - : (std::max)(1,m_diagSize)*NumTraits::epsilon(); - } - - inline Index rows() const { return m_rows; } - inline Index cols() const { return m_cols; } - - private: - void allocate(Index rows, Index cols, unsigned int computationOptions); - - static void check_template_parameters() - { - EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); - } - - protected: - MatrixUType m_matrixU; - MatrixVType m_matrixV; - SingularValuesType m_singularValues; - WorkMatrixType m_workMatrix; - bool m_isInitialized, m_isAllocated, m_usePrescribedThreshold; - bool m_computeFullU, m_computeThinU; - bool m_computeFullV, m_computeThinV; - unsigned int m_computationOptions; - Index m_nonzeroSingularValues, m_rows, m_cols, m_diagSize; - RealScalar m_prescribedThreshold; - - template - 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; - MatrixType m_scaledMatrix; -}; - -template -void JacobiSVD::allocate(Index rows, Index cols, unsigned int computationOptions) -{ - eigen_assert(rows >= 0 && cols >= 0); - - if (m_isAllocated && - rows == m_rows && - cols == m_cols && - computationOptions == m_computationOptions) - { - return; - } - - m_rows = rows; - m_cols = cols; - m_isInitialized = false; - m_isAllocated = true; - m_computationOptions = computationOptions; - m_computeFullU = (computationOptions & ComputeFullU) != 0; - m_computeThinU = (computationOptions & ComputeThinU) != 0; - m_computeFullV = (computationOptions & ComputeFullV) != 0; - m_computeThinV = (computationOptions & ComputeThinV) != 0; - eigen_assert(!(m_computeFullU && m_computeThinU) && "JacobiSVD: you can't ask for both full and thin U"); - eigen_assert(!(m_computeFullV && m_computeThinV) && "JacobiSVD: you can't ask for both full and thin V"); - eigen_assert(EIGEN_IMPLIES(m_computeThinU || m_computeThinV, MatrixType::ColsAtCompileTime==Dynamic) && - "JacobiSVD: thin U and V are only available when your matrix has a dynamic number of columns."); - if (QRPreconditioner == FullPivHouseholderQRPreconditioner) - { - eigen_assert(!(m_computeThinU || m_computeThinV) && - "JacobiSVD: can't compute thin U or thin V with the FullPivHouseholderQR preconditioner. " - "Use the ColPivHouseholderQR preconditioner instead."); - } - m_diagSize = (std::min)(m_rows, m_cols); - m_singularValues.resize(m_diagSize); - if(RowsAtCompileTime==Dynamic) - m_matrixU.resize(m_rows, m_computeFullU ? m_rows - : m_computeThinU ? m_diagSize - : 0); - if(ColsAtCompileTime==Dynamic) - m_matrixV.resize(m_cols, m_computeFullV ? m_cols - : 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); - if(m_rows!=m_cols) m_scaledMatrix.resize(rows,cols); -} - -template -JacobiSVD& -JacobiSVD::compute(const MatrixType& matrix, unsigned int computationOptions) -{ - check_template_parameters(); - - using std::abs; - allocate(matrix.rows(), matrix.cols(), computationOptions); - - // currently we stop when we reach precision 2*epsilon as the last bit of precision can require an unreasonable number of iterations, - // only worsening the precision of U and V as we accumulate more rotations - const RealScalar precision = RealScalar(2) * NumTraits::epsilon(); - - // limit for very small denormal numbers to be considered zero in order to avoid infinite loops (see bug 286) - const RealScalar considerAsZero = RealScalar(2) * std::numeric_limits::denorm_min(); - - // Scaling factor to reduce over/under-flows - RealScalar scale = matrix.cwiseAbs().maxCoeff(); - if(scale==RealScalar(0)) scale = RealScalar(1); - - /*** step 1. The R-SVD step: we use a QR decomposition to reduce to the case of a square matrix */ - - if(m_rows!=m_cols) - { - m_scaledMatrix = matrix / scale; - m_qr_precond_morecols.run(*this, m_scaledMatrix); - m_qr_precond_morerows.run(*this, m_scaledMatrix); - } - else - { - m_workMatrix = matrix.block(0,0,m_diagSize,m_diagSize) / scale; - if(m_computeFullU) m_matrixU.setIdentity(m_rows,m_rows); - if(m_computeThinU) m_matrixU.setIdentity(m_rows,m_diagSize); - if(m_computeFullV) m_matrixV.setIdentity(m_cols,m_cols); - if(m_computeThinV) m_matrixV.setIdentity(m_cols, m_diagSize); - } - - /*** step 2. The main Jacobi SVD iteration. ***/ - - bool finished = false; - while(!finished) - { - finished = true; - - // do a sweep: for all index pairs (p,q), perform SVD of the corresponding 2x2 sub-matrix - - for(Index p = 1; p < m_diagSize; ++p) - { - for(Index q = 0; q < p; ++q) - { - // if this 2x2 sub-matrix is not diagonal already... - // notice that this comparison will evaluate to false if any NaN is involved, ensuring that NaN's don't - // keep us iterating forever. Similarly, small denormal numbers are considered zero. - using std::max; - RealScalar threshold = (max)(considerAsZero, precision * (max)(abs(m_workMatrix.coeff(p,p)), - abs(m_workMatrix.coeff(q,q)))); - // We compare both values to threshold instead of calling max to be robust to NaN (See bug 791) - if(abs(m_workMatrix.coeff(p,q))>threshold || abs(m_workMatrix.coeff(q,p)) > threshold) - { - finished = false; - - // perform SVD decomposition of 2x2 sub-matrix corresponding to indices p,q to make it diagonal - internal::svd_precondition_2x2_block_to_be_real::run(m_workMatrix, *this, p, q); - JacobiRotation j_left, j_right; - internal::real_2x2_jacobi_svd(m_workMatrix, p, q, &j_left, &j_right); - - // accumulate resulting Jacobi rotations - m_workMatrix.applyOnTheLeft(p,q,j_left); - if(computeU()) m_matrixU.applyOnTheRight(p,q,j_left.transpose()); - - m_workMatrix.applyOnTheRight(p,q,j_right); - if(computeV()) m_matrixV.applyOnTheRight(p,q,j_right); - } - } - } - } - - /*** step 3. The work matrix is now diagonal, so ensure it's positive so its diagonal entries are the singular values ***/ - - for(Index i = 0; i < m_diagSize; ++i) - { - RealScalar a = abs(m_workMatrix.coeff(i,i)); - m_singularValues.coeffRef(i) = a; - if(computeU() && (a!=RealScalar(0))) m_matrixU.col(i) *= m_workMatrix.coeff(i,i)/a; - } - - /*** step 4. Sort singular values in descending order and compute the number of nonzero singular values ***/ - - m_nonzeroSingularValues = m_diagSize; - for(Index i = 0; i < m_diagSize; i++) - { - Index pos; - RealScalar maxRemainingSingularValue = m_singularValues.tail(m_diagSize-i).maxCoeff(&pos); - if(maxRemainingSingularValue == RealScalar(0)) - { - m_nonzeroSingularValues = i; - break; - } - if(pos) - { - pos += i; - std::swap(m_singularValues.coeffRef(i), m_singularValues.coeffRef(pos)); - if(computeU()) m_matrixU.col(pos).swap(m_matrixU.col(i)); - if(computeV()) m_matrixV.col(pos).swap(m_matrixV.col(i)); - } - } - - m_singularValues *= scale; - - m_isInitialized = true; - return *this; -} - -namespace internal { -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef JacobiSVD<_MatrixType, QRPreconditioner> JacobiSVDType; - EIGEN_MAKE_SOLVE_HELPERS(JacobiSVDType,Rhs) - - template void evalTo(Dest& dst) const - { - eigen_assert(rhs().rows() == dec().rows()); - - // A = U S V^* - // So A^{-1} = V S^{-1} U^* - - Matrix tmp; - Index rank = dec().rank(); - - tmp.noalias() = dec().matrixU().leftCols(rank).adjoint() * rhs(); - tmp = dec().singularValues().head(rank).asDiagonal().inverse() * tmp; - dst = dec().matrixV().leftCols(rank) * tmp; - } -}; -} // end namespace internal - -/** \svd_module - * - * \return the singular value decomposition of \c *this computed by two-sided - * Jacobi transformations. - * - * \sa class JacobiSVD - */ -template -JacobiSVD::PlainObject> -MatrixBase::jacobiSvd(unsigned int computationOptions) const -{ - return JacobiSVD(*this, computationOptions); -} - -} // end namespace Eigen - -#endif // EIGEN_JACOBISVD_H diff --git a/splinter/src/SVD/UpperBidiagonalization.h b/splinter/src/SVD/UpperBidiagonalization.h deleted file mode 100644 index 587de37a5a..0000000000 --- a/splinter/src/SVD/UpperBidiagonalization.h +++ /dev/null @@ -1,148 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2010 Benoit Jacob -// -// 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. - -template class UpperBidiagonalization -{ - public: - - typedef _MatrixType MatrixType; - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime, - ColsAtCompileTimeMinusOne = internal::decrement_size::ret - }; - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; - typedef Matrix RowVectorType; - typedef Matrix ColVectorType; - typedef BandMatrix BidiagonalType; - typedef Matrix DiagVectorType; - typedef Matrix SuperDiagVectorType; - typedef HouseholderSequence< - const MatrixType, - CwiseUnaryOp, const Diagonal > - > HouseholderUSequenceType; - typedef HouseholderSequence< - const typename internal::remove_all::type, - Diagonal, - OnTheRight - > HouseholderVSequenceType; - - /** - * \brief Default Constructor. - * - * The default constructor is useful in cases in which the user intends to - * perform decompositions via Bidiagonalization::compute(const MatrixType&). - */ - UpperBidiagonalization() : m_householder(), m_bidiagonal(), m_isInitialized(false) {} - - UpperBidiagonalization(const MatrixType& matrix) - : m_householder(matrix.rows(), matrix.cols()), - m_bidiagonal(matrix.cols(), matrix.cols()), - m_isInitialized(false) - { - compute(matrix); - } - - UpperBidiagonalization& compute(const MatrixType& matrix); - - const MatrixType& householder() const { return m_householder; } - const BidiagonalType& bidiagonal() const { return m_bidiagonal; } - - const HouseholderUSequenceType householderU() const - { - eigen_assert(m_isInitialized && "UpperBidiagonalization is not initialized."); - return HouseholderUSequenceType(m_householder, m_householder.diagonal().conjugate()); - } - - const HouseholderVSequenceType householderV() // const here gives nasty errors and i'm lazy - { - eigen_assert(m_isInitialized && "UpperBidiagonalization is not initialized."); - return HouseholderVSequenceType(m_householder.conjugate(), m_householder.const_derived().template diagonal<1>()) - .setLength(m_householder.cols()-1) - .setShift(1); - } - - protected: - MatrixType m_householder; - BidiagonalType m_bidiagonal; - bool m_isInitialized; -}; - -template -UpperBidiagonalization<_MatrixType>& UpperBidiagonalization<_MatrixType>::compute(const _MatrixType& matrix) -{ - Index rows = matrix.rows(); - Index cols = matrix.cols(); - - eigen_assert(rows >= cols && "UpperBidiagonalization is only for matrices satisfying rows>=cols."); - - m_householder = matrix; - - ColVectorType temp(rows); - - for (Index k = 0; /* breaks at k==cols-1 below */ ; ++k) - { - Index remainingRows = rows - k; - Index remainingCols = cols - k - 1; - - // construct left householder transform in-place in m_householder - m_householder.col(k).tail(remainingRows) - .makeHouseholderInPlace(m_householder.coeffRef(k,k), - m_bidiagonal.template diagonal<0>().coeffRef(k)); - // apply householder transform to remaining part of m_householder on the left - m_householder.bottomRightCorner(remainingRows, remainingCols) - .applyHouseholderOnTheLeft(m_householder.col(k).tail(remainingRows-1), - m_householder.coeff(k,k), - temp.data()); - - if(k == cols-1) break; - - // construct right householder transform in-place in m_householder - m_householder.row(k).tail(remainingCols) - .makeHouseholderInPlace(m_householder.coeffRef(k,k+1), - m_bidiagonal.template diagonal<1>().coeffRef(k)); - // apply householder transform to remaining part of m_householder on the left - m_householder.bottomRightCorner(remainingRows-1, remainingCols) - .applyHouseholderOnTheRight(m_householder.row(k).tail(remainingCols-1).transpose(), - m_householder.coeff(k,k+1), - temp.data()); - } - m_isInitialized = true; - return *this; -} - -#if 0 -/** \return the Householder QR decomposition of \c *this. - * - * \sa class Bidiagonalization - */ -template -const UpperBidiagonalization::PlainObject> -MatrixBase::bidiagonalization() const -{ - return UpperBidiagonalization(eval()); -} -#endif - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_BIDIAGONALIZATION_H diff --git a/splinter/src/SparseCore/ConservativeSparseSparseProduct.h b/splinter/src/SparseCore/ConservativeSparseSparseProduct.h deleted file mode 100644 index 5c320e2d2d..0000000000 --- a/splinter/src/SparseCore/ConservativeSparseSparseProduct.h +++ /dev/null @@ -1,245 +0,0 @@ -// 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_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(Index k=0; k::Flags&RowMajorBit) ? RowMajor : ColMajor, - int RhsStorageOrder = (traits::Flags&RowMajorBit) ? RowMajor : ColMajor, - int ResStorageOrder = (traits::Flags&RowMajorBit) ? RowMajor : ColMajor> -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/splinter/src/SparseCore/MappedSparseMatrix.h b/splinter/src/SparseCore/MappedSparseMatrix.h deleted file mode 100644 index ab1a266a90..0000000000 --- a/splinter/src/SparseCore/MappedSparseMatrix.h +++ /dev/null @@ -1,181 +0,0 @@ -// 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; } - - bool isCompressed() const { return true; } - - //---------------------------------------- - // 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/splinter/src/SparseCore/SparseBlock.h b/splinter/src/SparseCore/SparseBlock.h deleted file mode 100644 index 4f4983508b..0000000000 --- a/splinter/src/SparseCore/SparseBlock.h +++ /dev/null @@ -1,539 +0,0 @@ -// 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 { - -template -class BlockImpl - : public SparseMatrixBase > -{ - typedef typename internal::remove_all::type _MatrixTypeNested; - typedef Block BlockType; -public: - enum { IsRowMajor = internal::traits::IsRowMajor }; -protected: - enum { OuterSize = IsRowMajor ? BlockRows : BlockCols }; -public: - EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType) - - class InnerIterator: public XprType::InnerIterator - { - typedef typename BlockImpl::Index Index; - public: - inline InnerIterator(const BlockType& xpr, Index outer) - : XprType::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 XprType::ReverseInnerIterator - { - typedef typename BlockImpl::Index Index; - public: - inline ReverseInnerIterator(const BlockType& xpr, Index outer) - : XprType::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 BlockImpl(const XprType& xpr, int i) - : m_matrix(xpr), m_outerStart(i), m_outerSize(OuterSize) - {} - - inline BlockImpl(const XprType& xpr, int startRow, int startCol, int blockRows, int blockCols) - : m_matrix(xpr), m_outerStart(IsRowMajor ? startRow : startCol), m_outerSize(IsRowMajor ? blockRows : blockCols) - {} - - inline const Scalar coeff(int row, int col) const - { - return m_matrix.coeff(row + IsRowMajor ? m_outerStart : 0, col +IsRowMajor ? 0 : m_outerStart); - } - - inline const Scalar coeff(int index) const - { - return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index : m_outerStart); - } - - 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 XprType::Nested m_matrix; - Index m_outerStart; - const internal::variable_if_dynamic m_outerSize; - - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl) - private: - Index nonZeros() const; -}; - - -/*************************************************************************** -* specialisation for SparseMatrix -***************************************************************************/ - -template -class BlockImpl,BlockRows,BlockCols,true,Sparse> - : public SparseMatrixBase,BlockRows,BlockCols,true> > -{ - typedef SparseMatrix<_Scalar, _Options, _Index> SparseMatrixType; - typedef typename internal::remove_all::type _MatrixTypeNested; - typedef Block BlockType; - typedef Block ConstBlockType; -public: - enum { IsRowMajor = internal::traits::IsRowMajor }; - EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType) -protected: - enum { OuterSize = IsRowMajor ? BlockRows : BlockCols }; -public: - - class InnerIterator: public SparseMatrixType::InnerIterator - { - public: - inline InnerIterator(const BlockType& xpr, Index outer) - : SparseMatrixType::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 SparseMatrixType::ReverseInnerIterator - { - public: - inline ReverseInnerIterator(const BlockType& xpr, Index outer) - : SparseMatrixType::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 BlockImpl(const SparseMatrixType& xpr, int i) - : m_matrix(xpr), m_outerStart(i), m_outerSize(OuterSize) - {} - - inline BlockImpl(const SparseMatrixType& xpr, int startRow, int startCol, int blockRows, int blockCols) - : m_matrix(xpr), m_outerStart(IsRowMajor ? startRow : startCol), m_outerSize(IsRowMajor ? blockRows : blockCols) - {} - - template - inline BlockType& 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 start = m_outerStart==0 ? 0 : matrix.outerIndexPtr()[m_outerStart]; // starting position of the current block - Index end = m_matrix.outerIndexPtr()[m_outerStart+m_outerSize.value()]; // ending posiiton of the current block - Index block_size = end - start; // available room in the current block - Index tail_size = m_matrix.outerIndexPtr()[m_matrix.outerSize()] - end; - - Index free_size = m_matrix.isCompressed() - ? Index(matrix.data().allocatedSize()) + block_size - : block_size; - - if(nnz>free_size) - { - // realloc manually to reduce copies - typename SparseMatrixType::Storage newdata(m_matrix.data().allocatedSize() - block_size + nnz); - - std::memcpy(&newdata.value(0), &m_matrix.data().value(0), start*sizeof(Scalar)); - std::memcpy(&newdata.index(0), &m_matrix.data().index(0), start*sizeof(Index)); - - std::memcpy(&newdata.value(start), &tmp.data().value(0), nnz*sizeof(Scalar)); - std::memcpy(&newdata.index(start), &tmp.data().index(0), nnz*sizeof(Index)); - - std::memcpy(&newdata.value(start+nnz), &matrix.data().value(end), tail_size*sizeof(Scalar)); - std::memcpy(&newdata.index(start+nnz), &matrix.data().index(end), tail_size*sizeof(Index)); - - newdata.resize(m_matrix.outerIndexPtr()[m_matrix.outerSize()] - block_size + nnz); - - matrix.data().swap(newdata); - } - else - { - // no need to realloc, simply copy the tail at its respective position and insert tmp - matrix.data().resize(start + nnz + tail_size); - - std::memmove(&matrix.data().value(start+nnz), &matrix.data().value(end), tail_size*sizeof(Scalar)); - std::memmove(&matrix.data().index(start+nnz), &matrix.data().index(end), tail_size*sizeof(Index)); - - std::memcpy(&matrix.data().value(start), &tmp.data().value(0), nnz*sizeof(Scalar)); - std::memcpy(&matrix.data().index(start), &tmp.data().index(0), nnz*sizeof(Index)); - } - - // update innerNonZeros - if(!m_matrix.isCompressed()) - for(Index j=0; j(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(); - } - - inline Scalar& coeffRef(int row, int col) - { - return m_matrix.const_cast_derived().coeffRef(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart)); - } - - inline const Scalar coeff(int row, int col) const - { - return m_matrix.coeff(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart)); - } - - inline const Scalar coeff(int index) const - { - return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index : m_outerStart); - } - - const Scalar& lastCoeff() const - { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(BlockImpl); - 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]; - } - - 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 SparseMatrixType::Nested m_matrix; - Index m_outerStart; - const internal::variable_if_dynamic m_outerSize; - -}; - - -template -class BlockImpl,BlockRows,BlockCols,true,Sparse> - : public SparseMatrixBase,BlockRows,BlockCols,true> > -{ - typedef SparseMatrix<_Scalar, _Options, _Index> SparseMatrixType; - typedef typename internal::remove_all::type _MatrixTypeNested; - typedef Block BlockType; -public: - enum { IsRowMajor = internal::traits::IsRowMajor }; - EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType) -protected: - enum { OuterSize = IsRowMajor ? BlockRows : BlockCols }; -public: - - class InnerIterator: public SparseMatrixType::InnerIterator - { - public: - inline InnerIterator(const BlockType& xpr, Index outer) - : SparseMatrixType::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 SparseMatrixType::ReverseInnerIterator - { - public: - inline ReverseInnerIterator(const BlockType& xpr, Index outer) - : SparseMatrixType::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 BlockImpl(const SparseMatrixType& xpr, int i) - : m_matrix(xpr), m_outerStart(i), m_outerSize(OuterSize) - {} - - inline BlockImpl(const SparseMatrixType& xpr, int startRow, int startCol, int blockRows, int blockCols) - : m_matrix(xpr), m_outerStart(IsRowMajor ? startRow : startCol), m_outerSize(IsRowMajor ? blockRows : blockCols) - {} - - inline const Scalar* valuePtr() const - { return m_matrix.valuePtr() + m_matrix.outerIndexPtr()[m_outerStart]; } - - inline const Index* innerIndexPtr() const - { return m_matrix.innerIndexPtr() + m_matrix.outerIndexPtr()[m_outerStart]; } - - inline const Index* outerIndexPtr() const - { return m_matrix.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(); - } - - inline const Scalar coeff(int row, int col) const - { - return m_matrix.coeff(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart)); - } - - inline const Scalar coeff(int index) const - { - return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index : m_outerStart); - } - - const Scalar& lastCoeff() const - { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(BlockImpl); - 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]; - } - - 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: - - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl) - - typename SparseMatrixType::Nested m_matrix; - Index m_outerStart; - const internal::variable_if_dynamic m_outerSize; -}; - -//---------- - -/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this - * is col-major (resp. row-major). - */ -template -typename SparseMatrixBase::InnerVectorReturnType SparseMatrixBase::innerVector(Index outer) -{ return InnerVectorReturnType(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 typename SparseMatrixBase::ConstInnerVectorReturnType SparseMatrixBase::innerVector(Index outer) const -{ return ConstInnerVectorReturnType(derived(), outer); } - -/** \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this - * is col-major (resp. row-major). - */ -template -typename SparseMatrixBase::InnerVectorsReturnType -SparseMatrixBase::innerVectors(Index outerStart, Index outerSize) -{ - return Block(derived(), - IsRowMajor ? outerStart : 0, IsRowMajor ? 0 : outerStart, - IsRowMajor ? outerSize : rows(), IsRowMajor ? cols() : 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 typename SparseMatrixBase::ConstInnerVectorsReturnType -SparseMatrixBase::innerVectors(Index outerStart, Index outerSize) const -{ - return Block(derived(), - IsRowMajor ? outerStart : 0, IsRowMajor ? 0 : outerStart, - IsRowMajor ? outerSize : rows(), IsRowMajor ? cols() : outerSize); - -} - -/** Generic implementation of sparse Block expression. - * Real-only. - */ -template -class BlockImpl - : public SparseMatrixBase >, internal::no_assignment_operator -{ - typedef typename internal::remove_all::type _MatrixTypeNested; - typedef Block BlockType; -public: - enum { IsRowMajor = internal::traits::IsRowMajor }; - EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType) - - /** Column or Row constructor - */ - inline BlockImpl(const XprType& xpr, int i) - : m_matrix(xpr), - m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0), - m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0), - m_blockRows(BlockRows==1 ? 1 : xpr.rows()), - m_blockCols(BlockCols==1 ? 1 : xpr.cols()) - {} - - /** Dynamic-size constructor - */ - inline BlockImpl(const XprType& xpr, int startRow, int startCol, int blockRows, int blockCols) - : m_matrix(xpr), m_startRow(startRow), m_startCol(startCol), m_blockRows(blockRows), m_blockCols(blockCols) - {} - - inline int rows() const { return m_blockRows.value(); } - inline int cols() const { return m_blockCols.value(); } - - inline Scalar& coeffRef(int row, int col) - { - return m_matrix.const_cast_derived() - .coeffRef(row + m_startRow.value(), col + m_startCol.value()); - } - - inline const Scalar coeff(int row, int col) const - { - return m_matrix.coeff(row + m_startRow.value(), col + m_startCol.value()); - } - - inline Scalar& coeffRef(int index) - { - return m_matrix.const_cast_derived() - .coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), - m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); - } - - inline const Scalar coeff(int index) const - { - return m_matrix - .coeff(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), - m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); - } - - inline const _MatrixTypeNested& nestedExpression() const { return m_matrix; } - - class InnerIterator : public _MatrixTypeNested::InnerIterator - { - typedef typename _MatrixTypeNested::InnerIterator Base; - const BlockType& m_block; - Index m_end; - public: - - EIGEN_STRONG_INLINE InnerIterator(const BlockType& block, Index outer) - : Base(block.derived().nestedExpression(), outer + (IsRowMajor ? block.m_startRow.value() : block.m_startCol.value())), - m_block(block), - m_end(IsRowMajor ? block.m_startCol.value()+block.m_blockCols.value() : block.m_startRow.value()+block.m_blockRows.value()) - { - while( (Base::operator bool()) && (Base::index() < (IsRowMajor ? m_block.m_startCol.value() : m_block.m_startRow.value())) ) - Base::operator++(); - } - - inline Index index() const { return Base::index() - (IsRowMajor ? m_block.m_startCol.value() : m_block.m_startRow.value()); } - inline Index outer() const { return Base::outer() - (IsRowMajor ? m_block.m_startRow.value() : m_block.m_startCol.value()); } - inline Index row() const { return Base::row() - m_block.m_startRow.value(); } - inline Index col() const { return Base::col() - m_block.m_startCol.value(); } - - inline operator bool() const { return Base::operator bool() && Base::index() < m_end; } - }; - class ReverseInnerIterator : public _MatrixTypeNested::ReverseInnerIterator - { - typedef typename _MatrixTypeNested::ReverseInnerIterator Base; - const BlockType& m_block; - Index m_begin; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const BlockType& block, Index outer) - : Base(block.derived().nestedExpression(), outer + (IsRowMajor ? block.m_startRow.value() : block.m_startCol.value())), - m_block(block), - m_begin(IsRowMajor ? block.m_startCol.value() : block.m_startRow.value()) - { - while( (Base::operator bool()) && (Base::index() >= (IsRowMajor ? m_block.m_startCol.value()+block.m_blockCols.value() : m_block.m_startRow.value()+block.m_blockRows.value())) ) - Base::operator--(); - } - - inline Index index() const { return Base::index() - (IsRowMajor ? m_block.m_startCol.value() : m_block.m_startRow.value()); } - inline Index outer() const { return Base::outer() - (IsRowMajor ? m_block.m_startRow.value() : m_block.m_startCol.value()); } - inline Index row() const { return Base::row() - m_block.m_startRow.value(); } - inline Index col() const { return Base::col() - m_block.m_startCol.value(); } - - inline operator bool() const { return Base::operator bool() && Base::index() >= m_begin; } - }; - protected: - friend class InnerIterator; - friend class ReverseInnerIterator; - - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl) - - typename XprType::Nested m_matrix; - const internal::variable_if_dynamic m_startRow; - const internal::variable_if_dynamic m_startCol; - const internal::variable_if_dynamic m_blockRows; - const internal::variable_if_dynamic m_blockCols; - private: - Index nonZeros() const; -}; - -} // end namespace Eigen - -#endif // EIGEN_SPARSE_BLOCK_H - diff --git a/splinter/src/SparseCore/SparseCwiseBinaryOp.h b/splinter/src/SparseCore/SparseCwiseBinaryOp.h deleted file mode 100644 index 5462737594..0000000000 --- a/splinter/src/SparseCore/SparseCwiseBinaryOp.h +++ /dev/null @@ -1,324 +0,0 @@ -// 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() - { - EIGEN_STATIC_ASSERT(( - (!internal::is_same::StorageKind, - typename internal::traits::StorageKind>::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; - - // NOTE: we have to prefix Index by "typename Lhs::" to avoid an ICE with VC11 - EIGEN_STRONG_INLINE InnerIterator(const CwiseBinaryOpImpl& binOp, typename Lhs::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 derived() = derived() - other.derived(); -} - -template -template -EIGEN_STRONG_INLINE Derived & -SparseMatrixBase::operator+=(const SparseMatrixBase& other) -{ - return derived() = derived() + other.derived(); -} - -template -template -EIGEN_STRONG_INLINE const typename SparseMatrixBase::template CwiseProductDenseReturnType::Type -SparseMatrixBase::cwiseProduct(const MatrixBase &other) const -{ - return typename CwiseProductDenseReturnType::Type(derived(), other.derived()); -} - -} // end namespace Eigen - -#endif // EIGEN_SPARSE_CWISE_BINARY_OP_H diff --git a/splinter/src/SparseCore/SparseCwiseUnaryOp.h b/splinter/src/SparseCore/SparseCwiseUnaryOp.h deleted file mode 100644 index 5a50c78030..0000000000 --- a/splinter/src/SparseCore/SparseCwiseUnaryOp.h +++ /dev/null @@ -1,163 +0,0 @@ -// 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 typename internal::conditional< - Lhs::IsRowMajor, - SparseDenseOuterProduct, - SparseDenseOuterProduct >::type Type; -}; - -template struct DenseSparseProductReturnType -{ - typedef DenseTimeSparseProduct Type; -}; - -template struct DenseSparseProductReturnType -{ - typedef typename internal::conditional< - Rhs::IsRowMajor, - SparseDenseOuterProduct, - SparseDenseOuterProduct >::type 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; - typedef typename SparseDenseOuterProduct::Index Index; - public: - EIGEN_STRONG_INLINE InnerIterator(const SparseDenseOuterProduct& prod, Index outer) - : Base(prod.lhs(), 0), m_outer(outer), m_factor(get(prod.rhs(), outer, typename internal::traits::StorageKind() )) - { } - - inline Index outer() const { return m_outer; } - inline Index row() const { return Transpose ? m_outer : Base::index(); } - inline Index col() const { return Transpose ? Base::index() : m_outer; } - - inline Scalar value() const { return Base::value() * m_factor; } - - protected: - static Scalar get(const _RhsNested &rhs, Index outer, Dense = Dense()) - { - return rhs.coeff(outer); - } - - static Scalar get(const _RhsNested &rhs, Index outer, Sparse = Sparse()) - { - typename Traits::_RhsNested::InnerIterator it(rhs, outer); - if (it && it.index()==0) - return it.value(); - - return Scalar(0); - } - - Index 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, const 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, const 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, const 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, const 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, const 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, const 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&); -}; - -} // end namespace Eigen - -#endif // EIGEN_SPARSEDENSEPRODUCT_H diff --git a/splinter/src/SparseCore/SparseDiagonalProduct.h b/splinter/src/SparseCore/SparseDiagonalProduct.h deleted file mode 100644 index 1bb590e64d..0000000000 --- a/splinter/src/SparseCore/SparseDiagonalProduct.h +++ /dev/null @@ -1,196 +0,0 @@ -// 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; - - // We do not want ReverseInnerIterator for diagonal-sparse products, - // but this dummy declaration is needed to make diag * sparse * diag compile. - class ReverseInnerIterator; - - 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, - const typename Rhs::ConstInnerVectorReturnType, - const typename Lhs::DiagonalVectorType>::InnerIterator -{ - typedef typename CwiseBinaryOp< - scalar_product_op, - const typename Rhs::ConstInnerVectorReturnType, - const typename Lhs::DiagonalVectorType>::InnerIterator Base; - typedef typename Lhs::Index Index; - Index m_outer; - public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.rhs().innerVector(outer) .cwiseProduct(expr.lhs().diagonal()), 0), m_outer(outer) - {} - - inline Index outer() const { return m_outer; } - inline Index col() const { return m_outer; } -}; - -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, - const typename Lhs::ConstInnerVectorReturnType, - const Transpose >::InnerIterator -{ - typedef typename CwiseBinaryOp< - scalar_product_op, - const typename Lhs::ConstInnerVectorReturnType, - const Transpose >::InnerIterator Base; - typedef typename Lhs::Index Index; - Index m_outer; - public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.lhs().innerVector(outer) .cwiseProduct(expr.rhs().diagonal().transpose()), 0), m_outer(outer) - {} - - inline Index outer() const { return m_outer; } - inline Index row() const { return m_outer; } -}; - -} // 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/splinter/src/SparseCore/SparseFuzzy.h b/splinter/src/SparseCore/SparseFuzzy.h deleted file mode 100644 index 45f36e9eb9..0000000000 --- a/splinter/src/SparseCore/SparseFuzzy.h +++ /dev/null @@ -1,26 +0,0 @@ -// 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/splinter/src/SparseCore/SparsePermutation.h b/splinter/src/SparseCore/SparsePermutation.h deleted file mode 100644 index 75e2100095..0000000000 --- a/splinter/src/SparseCore/SparsePermutation.h +++ /dev/null @@ -1,148 +0,0 @@ -// 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()); - Matrix sizes(m_matrix.outerSize()); - for(Index j=0; j tmp(m_matrix.rows(), m_matrix.cols()); - Matrix 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/splinter/src/SparseCore/SparseProduct.h b/splinter/src/SparseCore/SparseProduct.h deleted file mode 100644 index cf76630700..0000000000 --- a/splinter/src/SparseCore/SparseProduct.h +++ /dev/null @@ -1,188 +0,0 @@ -// 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; - typedef typename internal::traits::Index Index; - 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, const RealScalar& tolerance) - : m_lhs(lhs), m_rhs(rhs), m_tolerance(tolerance), m_conservative(false) - { - init(); - } - - SparseSparseProduct pruned(const Scalar& reference = 0, const RealScalar& epsilon = NumTraits::dummy_precision()) const - { - using std::abs; - return SparseSparseProduct(m_lhs,m_rhs,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/splinter/src/SparseCore/SparseSelfAdjointView.h b/splinter/src/SparseCore/SparseSelfAdjointView.h deleted file mode 100644 index 0eda96bc47..0000000000 --- a/splinter/src/SparseCore/SparseSelfAdjointView.h +++ /dev/null @@ -1,507 +0,0 @@ -// 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(); } - - /** \returns an expression of the matrix product between a sparse self-adjoint matrix \c *this and a sparse matrix \a rhs. - * - * Note that there is no algorithmic advantage of performing such a product compared to a general sparse-sparse matrix product. - * Indeed, the SparseSelfadjointView operand is first copied into a temporary SparseMatrix before computing the product. - */ - template - SparseSparseProduct - operator*(const SparseMatrixBase& rhs) const - { - return SparseSparseProduct(*this, rhs.derived()); - } - - /** \returns an expression of the matrix product between a sparse matrix \a lhs and a sparse self-adjoint matrix \a rhs. - * - * Note that there is no algorithmic advantage of performing such a product compared to a general sparse-sparse matrix product. - * Indeed, the SparseSelfadjointView operand is first copied into a temporary SparseMatrix before computing the product. - */ - template friend - SparseSparseProduct - operator*(const SparseMatrixBase& lhs, const SparseSelfAdjointView& rhs) - { - return SparseSparseProduct(lhs.derived(), rhs); - } - - /** 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, const 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, const 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, const Scalar& alpha) const - { - EIGEN_ONLY_USED_FOR_DEBUG(alpha); - // TODO use alpha - eigen_assert(alpha==Scalar(1) && "alpha != 1 is not implemented yet, sorry"); - typedef typename internal::remove_all::type _Lhs; - 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*/, const 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] = numext::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()); - SparseMatrix tmp; - internal::permute_symm_to_fullsymm(m_matrix,tmp,m_perm.indices().data()); - _dest = tmp; - } - - 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/splinter/src/SparseCore/SparseTranspose.h b/splinter/src/SparseCore/SparseTranspose.h deleted file mode 100644 index 76d031d52c..0000000000 --- a/splinter/src/SparseCore/SparseTranspose.h +++ /dev/null @@ -1,63 +0,0 @@ -// 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 and VC11 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; - typedef typename TransposeImpl::Index Index; - public: - - EIGEN_STRONG_INLINE InnerIterator(const TransposeImpl& trans, typename TransposeImpl::Index outer) - : Base(trans.derived().nestedExpression(), outer) - {} - typename TransposeImpl::Index row() const { return Base::col(); } - typename TransposeImpl::Index col() const { return Base::row(); } -}; - -template class TransposeImpl::ReverseInnerIterator - : public _MatrixTypeNested::ReverseInnerIterator -{ - typedef typename _MatrixTypeNested::ReverseInnerIterator Base; - typedef typename TransposeImpl::Index Index; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const TransposeImpl& xpr, typename TransposeImpl::Index outer) - : Base(xpr.derived().nestedExpression(), outer) - {} - typename TransposeImpl::Index row() const { return Base::col(); } - typename TransposeImpl::Index col() const { return Base::row(); } -}; - -} // end namespace Eigen - -#endif // EIGEN_SPARSETRANSPOSE_H diff --git a/splinter/src/SparseCore/SparseTriangularView.h b/splinter/src/SparseCore/SparseTriangularView.h deleted file mode 100644 index 333127b78e..0000000000 --- a/splinter/src/SparseCore/SparseTriangularView.h +++ /dev/null @@ -1,179 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 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_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, - SkipDiag = (Mode&ZeroDiag) ? 1 : 0, - 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; - typedef typename SparseTriangularView::Index Index; - public: - - EIGEN_STRONG_INLINE InnerIterator(const SparseTriangularView& view, Index outer) - : Base(view.nestedExpression(), outer), m_returnOne(false) - { - if(SkipFirst) - { - while((*this) && ((HasUnitDiag||SkipDiag) ? 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 (MatrixType::Flags&RowMajorBit ? Base::outer() : this->index()); } - inline Index col() const { return (MatrixType::Flags&RowMajorBit ? this->index() : Base::outer()); } - 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; - if(SkipFirst) return Base::operator bool(); - else - { - if (SkipDiag) return (Base::operator bool() && this->index() < this->outer()); - else return (Base::operator bool() && this->index() <= this->outer()); - } - } - protected: - bool m_returnOne; -}; - -template -class SparseTriangularView::ReverseInnerIterator : public MatrixTypeNestedCleaned::ReverseInnerIterator -{ - typedef typename MatrixTypeNestedCleaned::ReverseInnerIterator Base; - typedef typename SparseTriangularView::Index Index; - 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) && (SkipDiag ? this->index()>=outer : this->index()>outer)) - --(*this); - } - } - - EIGEN_STRONG_INLINE ReverseInnerIterator& 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 - { - if (SkipLast) return Base::operator bool() ; - else - { - if(SkipDiag) return (Base::operator bool() && this->index() > this->outer()); - else return (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/splinter/src/SparseCore/SparseView.h b/splinter/src/SparseCore/SparseView.h deleted file mode 100644 index 2820b39b84..0000000000 --- a/splinter/src/SparseCore/SparseView.h +++ /dev/null @@ -1,99 +0,0 @@ -// 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 typename MatrixType::Index 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) - - explicit SparseView(const MatrixType& mat, const Scalar& reference = Scalar(0), - const RealScalar &epsilon = NumTraits::dummy_precision()) - : m_matrix(mat), m_reference(reference), m_epsilon(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 -{ - typedef typename SparseView::Index Index; -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, - const typename NumTraits::Real& m_epsilon) const -{ - return SparseView(derived(), m_reference, m_epsilon); -} - -} // end namespace Eigen - -#endif diff --git a/splinter/src/bspline.cpp b/splinter/src/bspline.cpp new file mode 100644 index 0000000000..8530d2e719 --- /dev/null +++ b/splinter/src/bspline.cpp @@ -0,0 +1,429 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include "bspline.h" +#include "bspline_basis.h" +#include "kronecker_product.h" +#include "unsupported/Eigen/KroneckerProduct" +#include +#include +#include +#include "bspline_utils.h" +#include "knot_builders.h" + + +namespace SPLINTER +{ + +/** + * Constructors for multivariate B-spline using explicit data + */ +BSpline::BSpline(const std::vector °rees, + const std::vector> &knot_vectors, + unsigned int dim_y) + : Function(degrees.size(), dim_y), + basis(BSplineBasis(degrees, knot_vectors)), + control_points(DenseMatrix::Zero(basis.get_num_basis_functions(), dim_y)) +{ + check_control_points(); +} + +BSpline::BSpline(const std::vector °rees, + const std::vector> &knot_vectors, + const std::vector> &control_points) + : Function(knot_vectors.size(), control_points.at(0).size()), + basis(BSplineBasis(degrees, knot_vectors)), + control_points(std_to_eig_mat(control_points)) +{ + check_control_points(); +} + +/** + * Returns the function value at x + */ +std::vector BSpline::eval(const std::vector &x) const { + return eig_to_std_vec(eval(std_to_eig_vec(x))); +} + +DenseVector BSpline::eval(const DenseVector &x) const +{ + check_input(x); + DenseVector res = control_points.transpose()* eval_basis(x); + return res; +} + +/** + * Returns the (dimY x dimX) Jacobian evaluated at x + */ +DenseMatrix BSpline::eval_jacobian(const DenseVector &x) const +{ + check_input(x); + return control_points.transpose()* eval_basis_jacobian(x); +} + +/** + * Returns the Hessian evaluated at x. The Hessian is a (dim_y x dim_x x dim_x) tensor. + */ +std::vector>> BSpline::eval_hessian(const std::vector &x) const +{ + DenseVector eigX = std_to_eig_vec(x); + check_input(eigX); + + std::vector>> hessian; + + DenseMatrix identity = DenseMatrix::Identity(dim_x, dim_x); + + DenseMatrix cp_copy = DenseMatrix(control_points); + + for (size_t i = 0; i < dim_y; ++i) + { + DenseMatrix H = DenseMatrix::Zero(1, 1); + DenseMatrix cp = cp_copy.col(i); + DenseMatrix caug = kroneckerProduct(identity, cp.transpose()); + DenseMatrix DB = basis.eval_basis_hessian(eigX); + + H = caug*DB; + +// std::cout << cp << std::endl; + + // Fill in upper triangular of Hessian + for (size_t j = 0; j < dim_x; ++j) + for (size_t k = j+1; k < dim_x; ++k) + H(j, k) = H(k, j); + + hessian.push_back(eig_to_std_mat(H)); + } + + return hessian; +} + +/** + * Evaluation of B-spline basis functions + */ +SparseVector BSpline::eval_basis(const DenseVector &x) const +{ +#ifndef NDEBUG + if (!is_supported(x)) + std::cout << "BSpline::eval_basis: Evaluation at point outside of support." << std::endl; +#endif // NDEBUG + + return basis.eval(x); +} + +/** + * Evaluation of B-spline basis Jacobian + */ +SparseMatrix BSpline::eval_basis_jacobian(const DenseVector &x) const +{ +#ifndef NDEBUG + if (!is_supported(x)) + std::cout << "BSpline::eval_basis_jacobian: Evaluation at point outside of support." << std::endl; +#endif // NDEBUG + + //SparseMatrix Bi = basis.eval_basis_jacobian(x); // Sparse Jacobian implementation + //SparseMatrix Bi = basis.eval_basis_jacobian2(x); // Sparse Jacobian implementation + DenseMatrix Bi = basis.eval_basis_jacobian_old(x); // Old Jacobian implementation + + return Bi.sparseView(); +} + +std::vector BSpline::get_num_basis_functions_per_variable() const +{ + std::vector ret; + for (unsigned int i = 0; i < dim_x; i++) + ret.push_back(basis.get_num_basis_functions(i)); + return ret; +} + +std::vector> BSpline::get_knot_vectors() const +{ + return basis.get_knot_vectors(); +} + +std::vector BSpline::get_basis_degrees() const +{ + return basis.get_basis_degrees(); +} + +std::vector BSpline::get_domain_upper_bound() const +{ + return basis.get_support_upper_bound(); +} + +std::vector BSpline::get_domain_lower_bound() const +{ + return basis.get_support_lower_bound(); +} + +void BSpline::set_control_points(const DenseMatrix &new_control_points) +{ + if (new_control_points.rows() != get_num_basis_functions()) + throw Exception("BSpline::set_control_points: Incompatible size of coefficient vector. " + + std::to_string(new_control_points.rows()) + " not equal to " + + std::to_string(get_num_basis_functions()) + "!"); + + this->control_points = new_control_points; + check_control_points(); +} + +void BSpline::linear_transform(const SparseMatrix &A) +{ + if (A.cols() != control_points.rows()) + throw Exception("BSpline::linear_transform: Incompatible size of linear transformation matrix."); + control_points = A*control_points; +} + +BSpline& BSpline::fit(const DataTable &data, Smoothing smoothing, double alpha, std::vector weights) +{ + if (data.get_dim_x() != get_dim_x()) { + throw Exception("BSpline::fit: Expected " + std::to_string(get_dim_x()) + " input variables."); + } + + if (data.get_dim_y() != get_dim_y()) { + throw Exception("BSpline::fit: Expected " + std::to_string(get_dim_y()) + " output variables."); + } + + if (alpha < 0) { + throw Exception("BSpline::fit: alpha must be non-negative."); + } + + if (weights.size() > 0 && data.get_num_samples() != weights.size()) { + throw Exception("BSpline::fit: number of weights must equal number of data points."); + } + +#ifndef NDEBUG + if (!data.is_grid_complete()) + std::cout << "BSpline::fit: Fitting B-spline to scattered data points (irregular grid of points)." << std::endl; +#endif // NDEBUG + + // Compute control points from samples and update B-spline + auto coefficients = compute_control_points(*this, data, smoothing, alpha, weights); + set_control_points(coefficients); + + return *this; +} + +void BSpline::check_control_points() const +{ + if (control_points.cols() != get_dim_y()) + throw Exception("BSpline::check_control_points: Inconsistent number of columns of control points matrix."); + if (control_points.rows() != get_num_basis_functions()) + throw Exception("BSpline::check_control_points: Inconsistent number of rows of control points matrix."); +} + +bool BSpline::is_supported(const DenseVector &x) const +{ + return basis.inside_support(x); +} + +void BSpline::reduce_support(const std::vector &lb, const std::vector &ub, bool regularize_knot_vectors) +{ + if (lb.size() != dim_x || ub.size() != dim_x) + throw Exception("BSpline::reduce_support: Inconsistent vector sizes!"); + + std::vector sl = basis.get_support_lower_bound(); + std::vector su = basis.get_support_upper_bound(); + + for (unsigned int dim = 0; dim < dim_x; dim++) + { + // Check if new domain is empty + if (ub.at(dim) <= lb.at(dim) || lb.at(dim) >= su.at(dim) || ub.at(dim) <= sl.at(dim)) + throw Exception("BSpline::reduce_support: Cannot reduce B-spline domain to empty set!"); + + // Check if new domain is a strict subset + if (su.at(dim) < ub.at(dim) || sl.at(dim) > lb.at(dim)) + throw Exception("BSpline::reduce_support: Cannot expand B-spline domain!"); + + // Tightest possible + sl.at(dim) = lb.at(dim); + su.at(dim) = ub.at(dim); + } + + if (regularize_knot_vectors) + { + this->regularize_knot_vectors(sl, su); + } + + // Remove knots and control points that are unsupported with the new bounds + if (!remove_unsupported_basis_functions(sl, su)) + { + throw Exception("BSpline::reduce_support: Failed to remove unsupported basis functions!"); + } +} + +void BSpline::global_knot_refinement() +{ + // Compute knot insertion matrix + SparseMatrix A = basis.refine_knots(); + + // Update control points + linear_transform(A); +} + +void BSpline::local_knot_refinement(const DenseVector &x) +{ + // Compute knot insertion matrix + SparseMatrix A = basis.refine_knots_locally(x); + + // Update control points + linear_transform(A); +} + +void BSpline::decompose_to_bezier() +{ + // Compute knot insertion matrix + SparseMatrix A = basis.decompose_to_bezier(); + + // Update control points + linear_transform(A); +} + +// Computes knot averages: assumes that basis is initialized! +DenseMatrix BSpline::compute_knot_averages() const +{ + // Calculate knot averages for each knot vector + std::vector mu_vectors; + for (unsigned int i = 0; i < dim_x; i++) + { + std::vector knots = basis.get_knot_vector(i); + DenseVector mu = DenseVector::Zero(basis.get_num_basis_functions(i)); + + for (unsigned int j = 0; j < basis.get_num_basis_functions(i); j++) + { + double knotAvg = 0; + for (unsigned int k = j+1; k <= j+ basis.get_basis_degree(i); k++) + { + knotAvg += knots.at(k); + } + mu(j) = knotAvg/ basis.get_basis_degree(i); + } + mu_vectors.push_back(mu); + } + + // Calculate vectors of ones (with same length as corresponding knot average vector) + std::vector knot_ones; + for (unsigned int i = 0; i < dim_x; i++) + knot_ones.push_back(DenseVector::Ones(mu_vectors.at(i).rows())); + + // Fill knot average matrix one column at the time + DenseMatrix knot_averages = DenseMatrix::Zero(basis.get_num_basis_functions(), dim_x); + + for (unsigned int i = 0; i < dim_x; i++) + { + DenseMatrix mu_ext(1,1); mu_ext(0,0) = 1; + for (unsigned int j = 0; j < dim_x; j++) + { + DenseMatrix temp = mu_ext; + if (i == j) + mu_ext = Eigen::kroneckerProduct(temp, mu_vectors.at(j)); + else + mu_ext = Eigen::kroneckerProduct(temp, knot_ones.at(j)); + } + if (mu_ext.rows() != basis.get_num_basis_functions()) + throw Exception("BSpline::compute_knot_averages: Incompatible size of knot average matrix."); + knot_averages.block(0, i, basis.get_num_basis_functions(), 1) = mu_ext; + } + + return knot_averages; +} + +void BSpline::insert_knots(double tau, unsigned int dim, unsigned int multiplicity) +{ + // Insert knots and compute knot insertion matrix + SparseMatrix A = basis.insert_knots(tau, dim, multiplicity); + + // Update control points + linear_transform(A); +} + +void BSpline::regularize_knot_vectors(const std::vector &lb, const std::vector &ub) +{ + // Add and remove controlpoints and knots to make the B-spline p-regular with support [lb, ub] + if (!(lb.size() == dim_x && ub.size() == dim_x)) + throw Exception("BSpline::regularize_knot_vectors: Inconsistent vector sizes."); + + for (unsigned int dim = 0; dim < dim_x; dim++) + { + unsigned int multiplicity_target = basis.get_basis_degree(dim) + 1; + + // Inserting many knots at the time (to save number of B-spline coefficient calculations) + // NOTE: This method generates knot insertion matrices with more nonzero elements than + // the method that inserts one knot at the time. This causes the preallocation of + // kronecker product matrices to become too small and the speed deteriorates drastically + // in higher dimensions because reallocation is necessary. This can be prevented by + // computing the number of nonzeros when preallocating memory (see my_kronecker_product). + int num_knots_lb = multiplicity_target - basis.get_knot_multiplicity(dim, lb.at(dim)); + if (num_knots_lb > 0) + { + insert_knots(lb.at(dim), dim, num_knots_lb); + } + + int num_knots_ub = multiplicity_target - basis.get_knot_multiplicity(dim, ub.at(dim)); + if (num_knots_ub > 0) + { + insert_knots(ub.at(dim), dim, num_knots_ub); + } + } +} + +bool BSpline::remove_unsupported_basis_functions(const std::vector &lb, const std::vector &ub) +{ + if (lb.size() != dim_x || ub.size() != dim_x) + throw Exception("BSpline::remove_unsupported_basis_functions: Incompatible dimension of domain bounds."); + + SparseMatrix A = basis.reduce_support(lb, ub); + + // Remove unsupported control points (basis functions) + linear_transform(A); + + return true; +} + +void BSpline::to_json(const std::string &filename) const { + SPLINTER::bspline_to_json(*this, filename); +} + +BSpline BSpline::from_json(const std::string &filename) { + return SPLINTER::bspline_from_json(filename); +} + +std::string BSpline::get_description() const +{ + std::string description("BSpline of degree"); + auto degrees = get_basis_degrees(); + // See if all degrees are the same. + bool equal = true; + for (size_t i = 1; i < degrees.size(); ++i) + { + equal = equal && (degrees.at(i) == degrees.at(i-1)); + } + + if(equal) + { + description.append(" "); + description.append(std::to_string(degrees.at(0))); + } + else + { + description.append("s ("); + for (size_t i = 0; i < degrees.size(); ++i) + { + description.append(std::to_string(degrees.at(i))); + if (i + 1 < degrees.size()) + { + description.append(", "); + } + } + description.append(")"); + } + + return description; +} + +} // namespace SPLINTER diff --git a/splinter/src/bspline_basis.cpp b/splinter/src/bspline_basis.cpp new file mode 100644 index 0000000000..b114959691 --- /dev/null +++ b/splinter/src/bspline_basis.cpp @@ -0,0 +1,456 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include "bspline_basis.h" +#include "unsupported/Eigen/KroneckerProduct" +#include "kronecker_product.h" +#include + + +namespace SPLINTER +{ + +BSplineBasis::BSplineBasis(std::vector degrees, const std::vector< std::vector > &knot_vectors) + : num_variables(knot_vectors.size()) +{ + if (knot_vectors.size() != degrees.size()) + throw Exception("BSplineBasis::BSplineBasis: Number of knot vectors is not equal to number of degrees."); + + // Set univariate bases + bases.clear(); + for (unsigned int i = 0; i < num_variables; i++) + { + bases.emplace_back(BSplineBasis1D(degrees.at(i), knot_vectors.at(i))); + + // Adjust target number of basis functions used in e.g. refinement + if (num_variables > 2) + { + // One extra knot is allowed + bases.at(i).set_num_basis_functions_target((degrees.at(i) + 1) + 1); // Minimum degree+1 + } + } +} + +SparseVector BSplineBasis::eval(const DenseVector &x) const +{ + // Evaluate basis functions for each variable i and compute the tensor product of the function values + std::vector basis_function_values; + + for (int var = 0; var < x.size(); var++) + basis_function_values.push_back(bases.at(var).eval(x(var))); + + return kronecker_product_vectors(basis_function_values); +} + +// Old implementation of Jacobian +DenseMatrix BSplineBasis::eval_basis_jacobian_old(const DenseVector &x) const +{ + // Jacobian basis matrix + DenseMatrix J; + J.setZero(get_num_basis_functions(), num_variables); + + // Calculate partial derivatives + for (unsigned int i = 0; i < num_variables; i++) + { + // One column in basis jacobian + DenseVector bi; bi.setOnes(1); + for (unsigned int j = 0; j < num_variables; j++) + { + DenseVector temp = bi; + DenseVector xi; + if (j == i) + { + // Differentiated basis + xi = bases.at(j).eval_first_derivative(x(j)); + } + else + { + // Normal basis + xi = bases.at(j).eval(x(j)); + } + + bi = kroneckerProduct(temp, xi); + } + + // Fill out column + J.block(0,i,bi.rows(),1) = bi.block(0,0,bi.rows(),1); + } + + return J; +} + +// NOTE: does not pass tests +SparseMatrix BSplineBasis::eval_basis_jacobian(const DenseVector &x) const +{ + // Jacobian basis matrix + SparseMatrix J(get_num_basis_functions(), num_variables); + //J.setZero(num_basis_functions(), numInputs); + + // Calculate partial derivatives + for (unsigned int i = 0; i < num_variables; ++i) + { + // One column in basis jacobian + std::vector values(num_variables); + + for (unsigned int j = 0; j < num_variables; ++j) + { + if (j == i) + { + // Differentiated basis + values.at(j) = bases.at(j).eval_derivative(x(j), 1); + } + else + { + // Normal basis + values.at(j) = bases.at(j).eval(x(j)); + } + } + + SparseVector Ji = kronecker_product_vectors(values); + + // Fill out column i + for (int k = 0; k < Ji.outerSize(); ++k) + { + for (SparseVector::InnerIterator it(Ji, k); it; ++it) + { + if (it.value() != 0) + J.insert(it.row(), i) = it.value(); + } + } + //J.block(0,i,Ji.rows(),1) = bi.block(0,0,Ji.rows(),1); + } + + J.makeCompressed(); + + return J; +} + +SparseMatrix BSplineBasis::eval_basis_jacobian2(const DenseVector &x) const +{ + // Jacobian basis matrix + SparseMatrix J(get_num_basis_functions(), num_variables); + + // Evaluate B-spline basis functions before looping + std::vector funcValues(num_variables); + std::vector gradValues(num_variables); + + for (unsigned int i = 0; i < num_variables; ++i) + { + funcValues[i] = bases.at(i).eval(x(i)); + gradValues[i] = bases.at(i).eval_first_derivative(x(i)); + } + + // Calculate partial derivatives + for (unsigned int i = 0; i < num_variables; i++) + { + std::vector values(num_variables); + + for (unsigned int j = 0; j < num_variables; j++) + { + if (j == i) + values.at(j) = gradValues.at(j); // Differentiated basis + else + values.at(j) = funcValues.at(j); // Normal basis + } + + SparseVector Ji = kronecker_product_vectors(values); + + // Fill out column + for (SparseVector::InnerIterator it(Ji); it; ++it) + J.insert(it.row(),i) = it.value(); + } + + return J; +} + +SparseMatrix BSplineBasis::eval_basis_hessian(const DenseVector &x) const +{ + // Hessian basis matrix + /* Hij = B1 x ... x DBi x ... x DBj x ... x Bn + * (Hii = B1 x ... x DDBi x ... x Bn) + * Where B are basis functions evaluated at x, + * DB are the derivative of the basis functions, + * and x is the kronecker product. + * Hij is in R^(numBasisFunctions x 1) + * so that basis hessian H is in R^(num_basis_functions*numInputs x numInputs) + * The real B-spline Hessian is calculated as (c^T x 1^(numInputs x 1))*H + */ + SparseMatrix H(get_num_basis_functions()*num_variables, num_variables); + //H.setZero(num_basis_functions()*numInputs, numInputs); + + // Calculate partial derivatives + // Utilizing that Hessian is symmetric + // Filling out lower left triangular + for (unsigned int i = 0; i < num_variables; i++) // row + { + for (unsigned int j = 0; j <= i; j++) // col + { + // One column in basis jacobian + SparseMatrix Hi(1,1); + Hi.insert(0,0) = 1; + + for (unsigned int k = 0; k < num_variables; k++) + { + SparseMatrix temp = Hi; + SparseMatrix Bk; + if (i == j && k == i) + { + // Diagonal element + Bk = bases.at(k).eval_derivative(x(k), 2); + } + else if (k == i || k == j) + { + Bk = bases.at(k).eval_derivative(x(k), 1); + } + else + { + Bk = bases.at(k).eval(x(k)); + } + Hi = kroneckerProduct(temp, Bk); + } + + // Fill out column + for (int k = 0; k < Hi.outerSize(); ++k) + { + for (SparseMatrix::InnerIterator it(Hi, k); it; ++it) + { + if (it.value() != 0) + { + int row = i * get_num_basis_functions() + it.row(); + int col = j; + H.insert(row, col) = it.value(); + } + } + } + } + } + + H.makeCompressed(); + + return H; +} + +SparseMatrix BSplineBasis::insert_knots(double tau, unsigned int dim, unsigned int multiplicity) +{ + SparseMatrix A(1, 1); + A.insert(0, 0) = 1; + + // Calculate multivariate knot insertion matrix + for (unsigned int i = 0; i < num_variables; i++) + { + SparseMatrix temp = A; + SparseMatrix Ai; + + if (i == dim) + { + // Build knot insertion matrix + Ai = bases.at(i).insert_knots(tau, multiplicity); + } + else + { + // No insertion - identity matrix + int m = bases.at(i).get_num_basis_functions(); + Ai.resize(m, m); + Ai.setIdentity(); + } + +// A = kroneckerProduct(temp, Ai); + A = my_kronecker_product(temp, Ai); + } + + A.makeCompressed(); + + return A; +} + +SparseMatrix BSplineBasis::refine_knots() +{ + SparseMatrix A(1, 1); + A.insert(0, 0) = 1; + + for (unsigned int i = 0; i < num_variables; i++) + { + SparseMatrix temp = A; + SparseMatrix Ai = bases.at(i).refine_knots(); + + //A = kroneckerProduct(temp, Ai); + A = my_kronecker_product(temp, Ai); + } + + A.makeCompressed(); + + return A; +} + +SparseMatrix BSplineBasis::refine_knots_locally(const DenseVector &x) +{ + SparseMatrix A(1,1); + A.insert(0,0) = 1; + + for (unsigned int i = 0; i < num_variables; i++) + { + SparseMatrix temp = A; + SparseMatrix Ai = bases.at(i).refine_knots_locally(x(i)); + + //A = kroneckerProduct(temp, Ai); + A = my_kronecker_product(temp, Ai); + } + + A.makeCompressed(); + + return A; +} + +SparseMatrix BSplineBasis::decompose_to_bezier() +{ + SparseMatrix A(1,1); + A.insert(0,0) = 1; + + for (unsigned int i = 0; i < num_variables; i++) + { + SparseMatrix temp = A; + SparseMatrix Ai = bases.at(i).decompose_to_bezier(); + + //A = kroneckerProduct(temp, Ai); + A = my_kronecker_product(temp, Ai); + } + + A.makeCompressed(); + + return A; +} + +SparseMatrix BSplineBasis::reduce_support(const std::vector &lb, const std::vector &ub) +{ + if (lb.size() != ub.size() || lb.size() != num_variables) + throw Exception("BSplineBasis::reduce_support: Incompatible dimension of domain bounds."); + + SparseMatrix A(1, 1); + A.insert(0, 0) = 1; + + for (unsigned int i = 0; i < num_variables; i++) + { + SparseMatrix temp = A; + SparseMatrix Ai = bases.at(i).reduce_support(lb.at(i), ub.at(i)); + + //A = kroneckerProduct(temp, Ai); + A = my_kronecker_product(temp, Ai); + } + + A.makeCompressed(); + + return A; +} + +std::vector BSplineBasis::get_basis_degrees() const +{ + std::vector degrees; + for (const auto& basis : bases) + degrees.push_back(basis.get_basis_degree()); + return degrees; +} + +unsigned int BSplineBasis::get_basis_degree(unsigned int dim) const +{ + return bases.at(dim).get_basis_degree(); +} + +unsigned int BSplineBasis::get_num_basis_functions(unsigned int dim) const +{ + return bases.at(dim).get_num_basis_functions(); +} + +unsigned int BSplineBasis::get_num_basis_functions() const +{ + unsigned int prod = 1; + for (unsigned int dim = 0; dim < num_variables; dim++) + { + prod *= bases.at(dim).get_num_basis_functions(); + } + return prod; +} + +BSplineBasis1D BSplineBasis::get_single_basis(unsigned int dim) +{ + return bases.at(dim); +} + +std::vector BSplineBasis::get_knot_vector(int dim) const +{ + return bases.at(dim).get_knot_vector(); +} + +std::vector< std::vector > BSplineBasis::get_knot_vectors() const +{ + std::vector< std::vector > knots; + for (unsigned int i = 0; i < num_variables; i++) + knots.push_back(bases.at(i).get_knot_vector()); + return knots; +} + +unsigned int BSplineBasis::get_knot_multiplicity(unsigned int dim, double tau) const +{ + return bases.at(dim).knot_multiplicity(tau); +} + +std::vector BSplineBasis::get_num_basis_functions_target() const +{ + std::vector ret; + for (unsigned int dim = 0; dim < num_variables; dim++) + { + ret.push_back(bases.at(dim).get_num_basis_functions_target() ); + } + return ret; +} + +unsigned int BSplineBasis::num_supported() const +{ + unsigned int ret = 1; + for (unsigned int dim = 0; dim < num_variables; dim++) + { + ret *= (bases.at(dim).get_basis_degree() + 1); + } + return ret; +} + +bool BSplineBasis::inside_support(const DenseVector &x) const +{ + for (unsigned int dim = 0; dim < num_variables; dim++) + { + if (!bases.at(dim).is_supported(x(dim))) + { + return false; + } + } + return true; +} + +std::vector BSplineBasis::get_support_lower_bound() const +{ + std::vector lb; + for (unsigned int dim = 0; dim < num_variables; dim++) + { + std::vector knots = bases.at(dim).get_knot_vector(); + lb.push_back(knots.front()); + } + return lb; +} + +std::vector BSplineBasis::get_support_upper_bound() const +{ + std::vector ub; + for (unsigned int dim = 0; dim < num_variables; dim++) + { + std::vector knots = bases.at(dim).get_knot_vector(); + ub.push_back(knots.back()); + } + return ub; +} + +} // namespace SPLINTER diff --git a/splinter/src/bspline_basis_1d.cpp b/splinter/src/bspline_basis_1d.cpp new file mode 100644 index 0000000000..e50be1d276 --- /dev/null +++ b/splinter/src/bspline_basis_1d.cpp @@ -0,0 +1,574 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include +#include +#include +#include +#include + +namespace SPLINTER +{ + +BSplineBasis1D::BSplineBasis1D(unsigned int degree, const std::vector &knots) + : degree(degree), + knots(KnotVector(knots)), + target_num_basis_functions((degree+1)+2*degree+1) // Minimum p+1 +{ + // Check that knot vector is (p+1)-regular + if (!this->knots.is_regular(degree)) + throw Exception("BSplineBasis1D::BSplineBasis1D: Knot vector is not regular."); +} + +SparseVector BSplineBasis1D::eval(double x) const +{ + SparseVector values(get_num_basis_functions()); + + if (!is_supported(x)) + return values; + + x = support_hack(x); + + auto index_supported = index_supported_basis_functions(x); + + values.reserve(index_supported.size()); + + // Evaluate nonzero basis functions + for (auto i : index_supported) + { + double val = de_boor_cox(x, i, degree); + if (fabs(val) > 1e-12) + values.insert(i) = val; + } + + // Alternative evaluation using basis matrix +// int knotIndex = indexHalfopenInterval(x); // knot index + +// SparseMatrix basisvalues2 = buildBsplineMatrix(x, knotIndex, 1); +// for (int i = 2; i <= basisDegree; i++) +// { +// SparseMatrix Ri = buildBsplineMatrix(x, knotIndex, i); +// basisvalues2 = basisvalues2*Ri; +// } +// basisvalues2.makeCompressed(); + +// assert(basisvalues2.rows() == 1); +// assert(basisvalues2.cols() == basisDegree + 1); + + return values; +} + +SparseVector BSplineBasis1D::eval_derivative(double x, unsigned int r) const +{ + // Evaluate rth derivative of basis functions at x + // Returns vector [D^(r)B_(u-p,p)(x) ... D^(r)B_(u,p)(x)] + // where u is the knot index and p is the degree + auto p = degree; + + // Continuity requirement + if (p < r) + { + // Return zero-gradient + SparseVector DB(get_num_basis_functions()); + return DB; + } + + // TODO: Check for knot multiplicity here! + + x = support_hack(x); + + unsigned int knot_index = knots.index_interval(x); + + // Algorithm 3.18 from Lyche and Moerken (2011) + SparseMatrix B(1,1); + B.insert(0,0) = 1; + + for (unsigned int i = 1; i <= p-r; i++) + { + SparseMatrix R = build_basis_matrix(x, knot_index, i); + B = B*R; + } + + for (unsigned int i = p-r+1; i <= p; i++) + { + SparseMatrix DR = build_basis_matrix(x, knot_index, i, true); + B = B*DR; + } + double factorial = std::tgamma(p+1)/std::tgamma(p-r+1); + B = B*factorial; + + if (B.cols() != p+1) + throw Exception("BSplineBasis1D::eval_derivative: Wrong number of columns of B matrix."); + + // From row vector to extended column vector + SparseVector DB(get_num_basis_functions()); + DB.reserve(p+1); + unsigned int i = knot_index-p; // First insertion index + + if (i < 0) + throw Exception("BSplineBasis1D::eval_derivative: negative insertion index!"); + + for (int k = 0; k < B.outerSize(); ++k) + { + for (SparseMatrix::InnerIterator it(B, k); it; ++it) + { + DB.insert(i+it.col()) = it.value(); + } + } + + return DB; +} + +// Old implementation of first derivative of basis functions +SparseVector BSplineBasis1D::eval_first_derivative(double x) const +{ + SparseVector values(get_num_basis_functions()); + + x = support_hack(x); + + auto supportedBasisFunctions = index_supported_basis_functions(x); + + for (auto i : supportedBasisFunctions) + { + // Differentiate basis function + // Equation 3.35 in Lyche & Moerken (2011) + double b1 = de_boor_cox(x, i, degree - 1); + double b2 = de_boor_cox(x, i + 1, degree - 1); + + double t11 = knots.at(i); + double t12 = knots.at(i+degree); + double t21 = knots.at(i+1); + double t22 = knots.at(i+degree+1); + + (t12 == t11) ? b1 = 0 : b1 = b1/(t12-t11); + (t22 == t21) ? b2 = 0 : b2 = b2/(t22-t21); + + values.insert(i) = degree*(b1 - b2); + } + + return values; +} + +/* + * Used to evaluate basis functions - alternative to the recursive deBoorCox + * Builds B-spline matrix R_k in R^(k,k+1), or, if diff = true, the differentiated basis matrix DR_k in R^(k,k+1). + */ +SparseMatrix BSplineBasis1D::build_basis_matrix(double x, unsigned int u, unsigned int k, bool diff) const +{ + if (!(k >= 1 && k <= get_basis_degree())) { + throw Exception("BSplineBasis1D::build_basis_matrix: Incorrect input parameters!"); + } + +// assert(u >= basisDegree + 1); +// assert(u < ks.size() - basisDegree); + + auto rows = k; + auto cols = k+1; + SparseMatrix R(rows, cols); + R.reserve(Eigen::VectorXi::Constant(cols, 2)); + + for (unsigned int i = 0; i < rows; i++) + { + double dk = knots.at(u+1+i) - knots.at(u+1+i-k); + if (dk == 0) + { + continue; + } + else + { + if (diff) + { + // Insert diagonal element + R.insert(i,i) = -1/dk; + + // Insert super-diagonal element + R.insert(i,i+1) = 1/dk; + } + else + { + // Insert diagonal element + double a = (knots.at(u+1+i) - x)/dk; + if (!assert_near(a, .0)) + R.insert(i,i) = a; + + // Insert super-diagonal element + double b = (x - knots.at(u+1+i-k))/dk; + if (!assert_near(b, .0)) + R.insert(i,i+1) = b; + } + } + } + + R.makeCompressed(); + + return R; +} + +double BSplineBasis1D::de_boor_cox(double x, unsigned int i, unsigned int k) const +{ + if (k == 0) + { + if ((knots.at(i) <= x) && (x < knots.at(i+1))) + return 1; + else + return 0; + } + else + { + double s1,s2,r1,r2; + + s1 = de_boor_cox_coeff(x, knots.at(i), knots.at(i + k)); + s2 = de_boor_cox_coeff(x, knots.at(i + 1), knots.at(i + k + 1)); + + r1 = de_boor_cox(x, i, k - 1); + r2 = de_boor_cox(x, i + 1, k - 1); + + return s1*r1 + (1-s2)*r2; + } +} + +double BSplineBasis1D::de_boor_cox_coeff(double x, double x_min, double x_max) const +{ + if (x_min < x_max && x_min <= x && x <= x_max) + return (x - x_min)/(x_max - x_min); + return 0; +} + +// Insert knots and compute knot insertion matrix (to update control points) +SparseMatrix BSplineBasis1D::insert_knots(double tau, unsigned int multiplicity) +{ + if (!is_supported(tau)) + throw Exception("BSplineBasis1D::insert_knots: Cannot insert knot outside domain!"); + + if (knot_multiplicity(tau) + multiplicity > degree + 1) + throw Exception("BSplineBasis1D::insert_knots: Knot multiplicity is too high!"); + + // New knot vector + int index = knots.index_interval(tau); + + std::vector extended_knots = knots.get_values(); + for (unsigned int i = 0; i < multiplicity; i++) + extended_knots.insert(extended_knots.begin()+index+1, tau); + + if (!KnotVector(extended_knots).is_regular(degree)) + throw Exception("BSplineBasis1D::insert_knots: New knot vector is not regular!"); + + // Return knot insertion matrix + SparseMatrix A = build_knot_insertion_matrix(extended_knots); + + // Update knots + knots = KnotVector(extended_knots); + + return A; +} + +SparseMatrix BSplineBasis1D::refine_knots() +{ + // Build refine knot vector + std::vector refinedKnots = knots.get_values(); + + unsigned int targetNumKnots = target_num_basis_functions + degree + 1; + while (refinedKnots.size() < targetNumKnots) + { + int index = index_longest_interval(refinedKnots); + double newKnot = (refinedKnots.at(index) + refinedKnots.at(index+1))/2.0; + refinedKnots.insert(std::lower_bound(refinedKnots.begin(), refinedKnots.end(), newKnot), newKnot); + } + + if (!KnotVector(refinedKnots).is_regular(degree)) + throw Exception("BSplineBasis1D::refine_knots: New knot vector is not regular!"); + + if (!knots.is_refinement(refinedKnots)) + throw Exception("BSplineBasis1D::refine_knots: New knot vector is not a proper refinement!"); + + // Return knot insertion matrix + SparseMatrix A = build_knot_insertion_matrix(refinedKnots); + + // Update knots + knots = KnotVector(refinedKnots); + + return A; +} + +SparseMatrix BSplineBasis1D::refine_knots_locally(double x) +{ + if (!is_supported(x)) + throw Exception("BSplineBasis1D::refine_knots_locally: Cannot refine outside support!"); + + if (get_num_basis_functions() >= get_num_basis_functions_target() + || assert_near(knots.front(), knots.back())) + { + unsigned int n = get_num_basis_functions(); + DenseMatrix A = DenseMatrix::Identity(n, n); + return A.sparseView(); + } + + // Refined knot vector + std::vector refinedKnots = knots.get_values(); + + auto upper = std::lower_bound(refinedKnots.begin(), refinedKnots.end(), x); + + // Check left boundary + if (upper == refinedKnots.begin()) + std::advance(upper, degree+1); + + // Get previous iterator + auto lower = std::prev(upper); + + // Do not insert if upper and lower bounding knot are close + if (assert_near(*upper, *lower)) + { + unsigned int n = get_num_basis_functions(); + DenseMatrix A = DenseMatrix::Identity(n,n); + return A.sparseView(); + } + + // Insert knot at x + double insertVal = x; + + // Adjust x if it is on or close to a knot + if (knot_multiplicity(x) > 0 + || assert_near(*upper, x, 1e-6, 1e-6) + || assert_near(*lower, x, 1e-6, 1e-6)) + { + insertVal = (*upper + *lower)/2.0; + } + + // Insert new knot + refinedKnots.insert(upper, insertVal); + + if (!KnotVector(refinedKnots).is_regular(degree)) + throw Exception("BSplineBasis1D::refine_knots_locally: New knot vector is not regular!"); + + if (!knots.is_refinement(refinedKnots)) + throw Exception("BSplineBasis1D::refine_knots_locally: New knot vector is not a proper refinement!"); + + // Build knot insertion matrix + SparseMatrix A = build_knot_insertion_matrix(refinedKnots); + + // Update knots + knots = KnotVector(refinedKnots); + + return A; +} + +SparseMatrix BSplineBasis1D::decompose_to_bezier() +{ + // Build refine knot vector + std::vector refined_knots = knots.get_values(); + + // Start at first knot and add knots until all knots have multiplicity degree + 1 + std::vector::iterator knoti = refined_knots.begin(); + while (knoti != refined_knots.end()) + { + // Insert new knots + int mult = degree + 1 - knot_multiplicity(*knoti); + if (mult > 0) + { + std::vector newKnots(mult, *knoti); + refined_knots.insert(knoti, newKnots.begin(), newKnots.end()); + } + + // Advance to next knot + knoti = std::upper_bound(refined_knots.begin(), refined_knots.end(), *knoti); + } + + if (!KnotVector(refined_knots).is_regular(degree)) + throw Exception("BSplineBasis1D::refine_knots: New knot vector is not regular!"); + + if (!knots.is_refinement(refined_knots)) + throw Exception("BSplineBasis1D::refine_knots: New knot vector is not a proper refinement!"); + + // Return knot insertion matrix + SparseMatrix A = build_knot_insertion_matrix(refined_knots); + + // Update knots + knots = KnotVector(refined_knots); + + return A; +} + +SparseMatrix BSplineBasis1D::build_knot_insertion_matrix(const std::vector &refined_knots) const +{ + if (!KnotVector(refined_knots).is_regular(degree)) + throw Exception("BSplineBasis1D::build_knot_insertion_matrix: New knot vector is not regular!"); + + if (!knots.is_refinement(refined_knots)) + throw Exception("BSplineBasis1D::build_knot_insertion_matrix: New knot vector is not a proper refinement!"); + + auto n = knots.size() - degree - 1; + auto m = refined_knots.size() - degree - 1; + + SparseMatrix A(m, n); + //A.resize(m,n); + A.reserve(Eigen::VectorXi::Constant(n, degree + 1)); + + // Build A row-by-row + for (unsigned int i = 0; i < m; i++) + { + int u = knots.index_interval(refined_knots.at(i)); + + SparseMatrix R(1,1); + R.insert(0,0) = 1; + + // For p > 0 + for (unsigned int j = 1; j <= degree; j++) + { + SparseMatrix Ri = build_basis_matrix(refined_knots.at(i + j), u, j); + R = R*Ri; + } + + // Size check + if (R.rows() != 1 || R.cols() != (int)degree + 1) + { + throw Exception("BSplineBasis1D::build_knot_insertion_matrix: Incorrect matrix dimensions!"); + } + + // Insert row values + int j = u - degree; // First insertion index + for (int k = 0; k < R.outerSize(); ++k) + for (SparseMatrix::InnerIterator it(R, k); it; ++it) + { + if (!assert_near(it.value(), .0)) + A.insert(i, j + it.col()) = it.value(); + } + } + + A.makeCompressed(); + + return A; +} + +/* + * The B-spline domain is the half-open domain [ knots.first(), knots.end() ). + * The hack checks if x is at the right boundary (if x = knots.end()), if so, + * a small number is subtracted from x, moving x into the half-open domain. + */ +double BSplineBasis1D::support_hack(double x) const +{ + if (x == knots.back()) + return std::nextafter(x, std::numeric_limits::lowest()); + return x; +} + +SparseMatrix BSplineBasis1D::reduce_support(double lb, double ub) +{ + // Check bounds + if (lb < knots.front() || ub > knots.back()) + throw Exception("BSplineBasis1D::reduce_support: Cannot increase support!"); + + unsigned int k = degree + 1; + + auto index_lower = index_supported_basis_functions(lb).front(); + auto index_upper = index_supported_basis_functions(ub).back(); + + // Check lower bound index + if (k != knot_multiplicity(knots.at(index_lower))) + { + int suggested_index = index_lower - 1; + if (0 <= suggested_index) + { + index_lower = suggested_index; + } + else + { + throw Exception("BSplineBasis1D::reduce_support: Suggested index is negative!"); + } + } + + // Check upper bound index + if (knot_multiplicity(ub) == k && knots.at(index_upper) == ub) + { + index_upper -= k; + } + + // New knot vector + std::vector si(knots.cbegin()+index_lower, knots.cbegin()+index_upper+k+1); + + // Construct selection matrix A + auto num_old = knots.size()-k; // Current number of basis functions + auto num_new = si.size()-k; // Number of basis functions after update + + if (num_old < num_new) + throw Exception("BSplineBasis1D::reduce_support: Number of basis functions is increased instead of reduced!"); + + DenseMatrix Ad = DenseMatrix::Zero(num_new, num_old); + Ad.block(0, index_lower, num_new, num_new) = DenseMatrix::Identity(num_new, num_new); + + // Update knots + knots = si; + + return Ad.sparseView(); +} + +unsigned int BSplineBasis1D::get_num_basis_functions() const +{ + return knots.size() - (degree + 1); +} + +unsigned int BSplineBasis1D::get_num_basis_functions_target() const +{ + return target_num_basis_functions; +} + +// Return indices of supporting basis functions at x +std::vector BSplineBasis1D::index_supported_basis_functions(double x) const +{ + if (!is_supported(x)) + throw Exception("BSplineBasis1D::index_supported_basis_functions: x not inside support!"); + + std::vector supported; + for (unsigned int i = 0; i < get_num_basis_functions(); ++i) + { + // Support of basis function i + if (knots.at(i) <= x && x < knots.at(i+degree+1)) + { + supported.push_back(i); + + if (supported.size() == degree + 1) + break; + } + } + + // Right edge case + if (assert_near(x, knots.back()) && knot_multiplicity(knots.back()) == degree + 1 && supported.size() < degree + 1) + { + auto last_basis_func = get_num_basis_functions()-1; + if (find(supported.begin(), supported.end(), last_basis_func) == supported.end()) + supported.push_back(last_basis_func); + } + + if (supported.empty()) + throw Exception("BSplineBasis1D::index_supported_basis_functions: No supporting basis functions"); + + if (supported.size() > degree + 1) + throw Exception("BSplineBasis1D::index_supported_basis_functions: Number of supporting basis functions larger than degree + 1!"); + + return supported; +} + +unsigned int BSplineBasis1D::index_longest_interval(const std::vector &vec) const +{ + double longest = 0; + double interval = 0; + unsigned int index = 0; + + for (unsigned int i = 0; i < vec.size() - 1; i++) + { + interval = vec.at(i+1) - vec.at(i); + if (longest < interval) + { + longest = interval; + index = i; + } + } + return index; +} + +} // namespace SPLINTER diff --git a/splinter/src/bspline_builders.cpp b/splinter/src/bspline_builders.cpp new file mode 100644 index 0000000000..3a74b7ff3f --- /dev/null +++ b/splinter/src/bspline_builders.cpp @@ -0,0 +1,54 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include "bspline_builders.h" + + +namespace SPLINTER +{ + +BSpline bspline_interpolator(const DataTable &data, unsigned int degree) +{ + auto dim_x = data.get_dim_x(); + auto dim_y = data.get_dim_y(); + auto degrees = std::vector(dim_x, degree); + auto knot_vectors = build_knot_vectors(data, degrees); + + return BSpline(degrees, knot_vectors, dim_y).fit(data); +} + +BSpline bspline_smoother(const DataTable &data, unsigned int degree, BSpline::Smoothing smoothing, double alpha, + std::vector weights) +{ + auto dim_x = data.get_dim_x(); + auto dim_y = data.get_dim_y(); + auto degrees = std::vector(dim_x, degree); + auto knot_vectors = build_knot_vectors(data, degrees); + + return BSpline(degrees, knot_vectors, dim_y).fit(data, smoothing, alpha, weights); +} + +BSpline bspline_unfitted(const DataTable &data, const std::vector °rees, KnotSpacing knot_spacing, + const std::vector &num_basis_functions) +{ + auto dim_x = data.get_dim_x(); + auto dim_y = data.get_dim_y(); + if (dim_x != num_basis_functions.size()) + throw Exception("Size of num_basis_functions " + std::to_string(num_basis_functions.size()) + + " does not match the input dimension " + std::to_string(dim_x) + " of the samples."); + + if (dim_y != degrees.size()) + throw Exception("Size of degrees " + std::to_string(degrees.size()) + " does not match the output dimensions " + + std::to_string(dim_y) + " of the samples."); + + auto knot_vectors = build_knot_vectors(data, degrees, knot_spacing, num_basis_functions); + return BSpline(degrees, knot_vectors, dim_y); +} + +} // namespace SPLINTER \ No newline at end of file diff --git a/splinter/src/bspline_utils.cpp b/splinter/src/bspline_utils.cpp new file mode 100644 index 0000000000..6d701503ec --- /dev/null +++ b/splinter/src/bspline_utils.cpp @@ -0,0 +1,296 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include "bspline_utils.h" +#include +#include +#include + +namespace SPLINTER +{ + +/** + * Find coefficients of B-spline by solving: + * min ||W*X*C - W*Y||^2 + alpha*||R||^2, + * where + * X = (m x n) matrix of n basis functions evaluated at m sample points, + * Y = vector of m sample points y-values (or x-values when calculating knot averages), + * C = B-spline coefficients (or knot averages), + * R = Regularization matrix (n x n), + * alpha = regularization parameter, + * W = Diagonal weight matrix (m x m). + * + * The optimal control point matrix C is the solution of the linear system of equations: + * (X'*W*X + alpha*R) C = X'*W*Y + * + * For performance gains, the various cases are solved as follows: + * 1) No regularization or weighting: XC = Y + * 2) Weighting, no regularization: WXC = WY + * 3) Regularization, no weighting: (X'X + alpha*R)C = X'Y + * 4) Regularization and weighting: (X'*W*X + alpha*R)C = X'*W*Y + * + * TODO: Use existing control points C0 as starting point and compute new control points as C = DeltaC + C0 + * + */ +DenseMatrix compute_control_points(const BSpline &bspline, const DataTable &data, BSpline::Smoothing smoothing, + double alpha, std::vector weights) +{ + unsigned int num_basis_functions = bspline.get_num_basis_functions(); + SparseMatrix X = compute_basis_function_matrix(bspline, data); + DenseMatrix Y = stack_sample_values(data); + + SparseMatrix A; // Left-hand side matrix + DenseMatrix B; // Right-hand side matrix + + // Weight matrix + if (weights.size() > 0) { + // NOTE: Consider using Eigen::DiagonalMatrix W() + // SparseMatrix W(num_samples, num_samples); + SparseMatrix W = compute_weight_matrix(weights); + A = W*X; + B = W*Y; + } else { + A = X; + B = Y; + } + + // Regularization + if (smoothing != BSpline::Smoothing::NONE) { + + // Regularization matrix + SparseMatrix R(num_basis_functions, num_basis_functions); + + if (smoothing == BSpline::Smoothing::IDENTITY) { + /* + * Tikhonov regularization (or ridge regression) with the Identity matrix + * See: https://en.wikipedia.org/wiki/Tikhonov_regularization + */ + auto I = SparseMatrix(num_basis_functions, num_basis_functions); + I.setIdentity(); + R = I; + } + else if (smoothing == BSpline::Smoothing::PSPLINE) { + /* + * The P-Spline is a smoothing B-spline which relaxes the interpolation constraints on the control points to allow + * smoother spline curves. It minimizes an objective which penalizes both deviation from sample points (to lower bias) + * and the magnitude of second derivatives (to lower variance). + * + * Regularization matrix is given as R = D'*D, where D is the second-order finite difference matrix + */ + SparseMatrix D = compute_second_order_finite_difference_matrix(bspline); + R = D.transpose()*D; + } + + // NOTE: Using eval to avoid aliasing + // NOTE2: consider changing regularization factor to (alpha/numSample) + A = (X.transpose()*A + alpha*R).eval(); + B = (X.transpose()*B).eval(); + } + + // Solve equation AC = B for control points C + DenseMatrix C; + + // Solve as dense if both the number of rows and columns of A are less than 100 + bool solve_as_dense = (std::max(A.rows(), A.cols()) < 100); + + if (!solve_as_dense) { + + #ifndef NDEBUG + std::cout << "compute_control_points: Computing B-spline control points using sparse solver." << std::endl; + #endif // NDEBUG + + if (A.rows() == A.cols()) { + // NOTE: If using SparseLU, the A matrix must be square + SparseLU s; + solve_as_dense = !s.solve(A, B, C); + } + else { + // Using SparseQR for non-square A matrix + SparseQR s; + solve_as_dense = !s.solve(A, B, C); + } + } + + if (solve_as_dense) { + + #ifndef NDEBUG + std::cout << "compute_control_points: Computing B-spline control points using dense solver." << std::endl; + #endif // NDEBUG + + DenseMatrix Ad = A.toDense(); + DenseQR s; +// DenseSVD s; + if (!s.solve(Ad, B, C)) { + throw Exception("compute_control_points: Failed to solve for B-spline control points."); + } + } + + return C; +} + +SparseMatrix compute_basis_function_matrix(const BSpline &bspline, const DataTable &data) +{ + unsigned int num_samples = data.get_num_samples(); + + SparseMatrix A(num_samples, bspline.get_num_basis_functions()); + + // Reserve memory for A. + // Assume ColMajor storage order, in which case the inner vectors of SparseMatrix are columns. + // If the storage order ever changes, change the reserve statement to: + // A.reserve( Eigen::VectorXi::Constant( num_samples, bspline.get_num_supported() ) ); + static_assert( A.IsRowMajor == false, "" ); + // Although the number of non-zero elements per row equals bspline.get_num_supported(), + // SparseMatrix::reserve requires a vector of size SparseMatrix::cols() a an argument; + Eigen::VectorXi reserve_sizes( A.cols() ); + // Assuming that non-zero elements in A are distributed randomly, the average number of non-zero elements per column is: + const double average_nnz_per_col = num_samples * bspline.get_num_supported() / bspline.get_num_basis_functions(); + // Add safety margin of sqrt(N), but don't exceed num_samples ( which otherwise would happen if e.g. bspline.get_num_supported() == bspline.get_num_basis_functions() ) + const int reserve_col_size = std::min( static_cast( average_nnz_per_col + sqrt( average_nnz_per_col ) ), static_cast(num_samples) ); + reserve_sizes.fill( reserve_col_size ); + A.reserve( reserve_sizes ); + + int i = 0; + for (auto it = data.cbegin(); it != data.cend(); ++it, ++i) + { + DenseVector xi = std_to_eig_vec(it->get_x()); + SparseVector basis_values = bspline.eval_basis(xi); + for (SparseVector::InnerIterator it2(basis_values); it2; ++it2) + A.insert(i, it2.index()) = it2.value(); + } + + A.makeCompressed(); + + return A; +} + +DenseMatrix stack_sample_values(const DataTable &data) +{ + DenseMatrix B = DenseMatrix::Zero(data.get_num_samples(), data.get_dim_y()); + + int i = 0; + for (auto it = data.cbegin(); it != data.cend(); ++it, ++i) + { + auto y = it->get_y(); + for (unsigned int j = 0; j < data.get_dim_y(); ++j) + B(i, j) = y.at(j); + } + return B; +} + +/** + * Function for generating second order finite-difference matrix, which is used for penalizing the + * (approximate) second derivative in control point calculation for P-splines. + */ +SparseMatrix compute_second_order_finite_difference_matrix(const BSpline &bspline) +{ + unsigned int num_variables = bspline.get_dim_x(); + + // Number of (total) basis functions - defines the number of columns in D + unsigned int num_cols = bspline.get_num_basis_functions(); + std::vector num_basis_functions = bspline.get_num_basis_functions_per_variable(); + + // Number of basis functions (and coefficients) in each variable + std::vector dims; + for (unsigned int i = 0; i < num_variables; i++) + dims.push_back(num_basis_functions.at(i)); + + std::reverse(dims.begin(), dims.end()); + + for (unsigned int i=0; i < num_variables; ++i) + if (num_basis_functions.at(i) < 3) + throw Exception("compute_second_order_finite_difference_matrix: Need at least three coefficients/basis functions per variable."); + + // Number of rows in D and in each block + int num_rows = 0; + std::vector< int > num_blk_rows; + for (unsigned int i = 0; i < num_variables; i++) + { + int prod = 1; + for (unsigned int j = 0; j < num_variables; j++) + { + if (i == j) + prod *= (dims[j] - 2); + else + prod *= dims[j]; + } + num_rows += prod; + num_blk_rows.push_back(prod); + } + + // Resize and initialize D + SparseMatrix D(num_rows, num_cols); + D.reserve(DenseVector::Constant(num_cols, 2*num_variables)); // D has no more than two elems per col per dim + + int i = 0; // Row index + // Loop though each dimension (each dimension has its own block) + for (unsigned int d = 0; d < num_variables; d++) + { + // Calculate left and right products + int left_prod = 1; + int right_prod = 1; + for (unsigned int k = 0; k < d; k++) + { + left_prod *= dims[k]; + } + for (unsigned int k = d+1; k < num_variables; k++) + { + right_prod *= dims[k]; + } + + // Loop through subblocks on the block diagonal + for (int j = 0; j < right_prod; j++) + { + // Start column of current subblock + int blkBaseCol = j*left_prod*dims[d]; + // Block rows [I -2I I] of subblock + for (unsigned int l = 0; l < (dims[d] - 2); l++) + { + // Special case for first dimension + if (d == 0) + { + int k = j*left_prod*dims[d] + l; + D.insert(i,k) = 1; + k += left_prod; + D.insert(i,k) = -2; + k += left_prod; + D.insert(i,k) = 1; + i++; + } + else + { + // Loop for identity matrix + for (int n = 0; n < left_prod; n++) + { + int k = blkBaseCol + l*left_prod + n; + D.insert(i,k) = 1; + k += left_prod; + D.insert(i,k) = -2; + k += left_prod; + D.insert(i,k) = 1; + i++; + } + } + } + } + } + + D.makeCompressed(); + + return D; +} + +SparseMatrix compute_weight_matrix(std::vector weights) +{ + // TODO: use DiagonalMatrix here + auto eig_weights = std_to_eig_vec(weights); + DenseMatrix D = eig_weights.asDiagonal(); + return D.sparseView(); +} + +} // namespace SPLINTER diff --git a/splinter/src/cinterface/bspline.cpp b/splinter/src/cinterface/bspline.cpp new file mode 100644 index 0000000000..fb8ba33690 --- /dev/null +++ b/splinter/src/cinterface/bspline.cpp @@ -0,0 +1,529 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include +#include "bspline.h" +#include "cinterface/utilities.h" + +using namespace SPLINTER; + +extern "C" +{ + +splinter_obj_ptr splinter_bspline_from_param(unsigned int dim_x, unsigned int dim_y, unsigned int *degrees, + double *knot_vectors, unsigned int *num_knots_per_vector, + double *control_points, unsigned int num_control_points) +{ + splinter_obj_ptr bspline = nullptr; + auto degrees_vec = get_vector(degrees, dim_x); + auto knot_vectors_vec_vec = get_vector_vector(knot_vectors, num_knots_per_vector, dim_x); + auto control_points_vec_vec = get_vector_vector(control_points, dim_y, num_control_points); + + try + { + bspline = (splinter_obj_ptr) new BSpline(degrees_vec, knot_vectors_vec_vec, control_points_vec_vec); + bsplines.insert(bspline); + } + catch (const Exception &e) + { + set_error_string(e.what()); + } + + return bspline; +} + +splinter_obj_ptr splinter_bspline_from_param_zero(unsigned int dim_x, + unsigned int dim_y, + unsigned int *degrees, + double *knot_vectors, + unsigned int *num_knots_per_vector) +{ + splinter_obj_ptr bspline = nullptr; + auto knot_vectors_vec_vec = get_vector_vector(knot_vectors, num_knots_per_vector, dim_x); + auto degrees_vec = get_vector(degrees, dim_x); + + try + { + bspline = (splinter_obj_ptr) new BSpline(degrees_vec, knot_vectors_vec_vec, dim_y); + bsplines.insert(bspline); + } + catch (const Exception &e) + { + set_error_string(e.what()); + } + + return bspline; +} + +int *splinter_bspline_get_knot_vector_sizes(splinter_obj_ptr bspline_ptr) +{ + auto bspline = get_bspline(bspline_ptr); + int *sizes = nullptr; + if (bspline != nullptr) + { + try + { + auto knot_vectors = bspline->get_knot_vectors(); + + sizes = (int *) malloc(knot_vectors.size() * sizeof (int)); + + if (sizes != nullptr) + { + int i = 0; + for (auto knot_vector : knot_vectors) + { + sizes[i++] = (int) knot_vector.size(); + } + } + else + { + set_error_string("Unable to allocate memory!"); + } + } + catch (const Exception &e) + { + set_error_string(e.what()); + } + } + return sizes; +} + +double *splinter_bspline_get_knot_vectors(splinter_obj_ptr bspline_ptr) +{ + auto bspline = get_bspline(bspline_ptr); + double *knot_vectors_as_array = nullptr; + if (bspline != nullptr) + { + try + { + auto knot_vectors = bspline->get_knot_vectors(); + + // Overkill, but some C++11 is nice + int total_n_elements = 0; + std::for_each(knot_vectors.cbegin(), knot_vectors.cend(), + [&total_n_elements](const std::vector &knot_vector) + { + total_n_elements += knot_vector.size(); + }); + knot_vectors_as_array = (double *) malloc(total_n_elements * sizeof (double)); + + if (knot_vectors_as_array != nullptr) + { + int i = 0; + for (auto knot_vector : knot_vectors) + { + // Even more unnecessary C++11 stuff + std::copy(knot_vector.begin(), knot_vector.end(), knot_vectors_as_array + i); + i += knot_vector.size(); + } + } + else + { + set_error_string("Unable to allocate memory!"); + } + } + catch (const Exception &e) + { + set_error_string(e.what()); + } + } + return knot_vectors_as_array; +} + +int splinter_bspline_get_num_control_points(splinter_obj_ptr bspline_ptr) +{ + auto bspline = get_bspline(bspline_ptr); + if (bspline != nullptr) + { + try + { + return bspline->get_num_control_points(); + } + catch (const Exception &e) + { + set_error_string(e.what()); + } + } + return -1; +} + +double *splinter_bspline_get_control_points(splinter_obj_ptr bspline_ptr) +{ + auto bspline = get_bspline(bspline_ptr); + double *control_points_as_array = nullptr; + if (bspline != nullptr) + { + try + { + auto control_points = bspline->get_control_points(); + + control_points_as_array = (double *) malloc(control_points.size() * sizeof (double)); + + if (control_points_as_array != nullptr) + { + for (int i = 0; i < control_points.rows(); ++i) + { + for (int j = 0; j < control_points.cols(); ++j) + { + control_points_as_array[i*control_points.cols() + j] = control_points(i, j); + } + } + } + else + { + set_error_string("Unable to allocate memory!"); + } + } + catch (const Exception &e) + { + set_error_string(e.what()); + } + } + return control_points_as_array; +} + +double *splinter_bspline_get_knot_averages(splinter_obj_ptr bspline_ptr) +{ + auto bspline = get_bspline(bspline_ptr); + double *knot_averages_as_array = nullptr; + if (bspline != nullptr) + { + try + { + auto knot_averages = bspline->get_knot_averages(); + + knot_averages_as_array = (double *) malloc(knot_averages.size() * sizeof (double)); + + if (knot_averages_as_array != nullptr) + { + for (int i = 0; i < knot_averages.rows(); ++i) + { + for (int j = 0; j < knot_averages.cols(); ++j) + { + knot_averages_as_array[i*knot_averages.cols() + j] = knot_averages(i, j); + } + } + } + else + { + set_error_string("Unable to allocate memory!"); + } + } + catch (const Exception &e) + { + set_error_string(e.what()); + } + } + return knot_averages_as_array; +} + +int *splinter_bspline_get_basis_degrees(splinter_obj_ptr bspline_ptr) +{ + auto bspline = get_bspline(bspline_ptr); + int *basis_degrees_as_array = nullptr; + if (bspline != nullptr) + { + try + { + auto basis_degrees = bspline->get_basis_degrees(); + + basis_degrees_as_array = (int *) malloc(basis_degrees.size() * sizeof (int)); + + if (basis_degrees_as_array != nullptr) + { + for (unsigned int i = 0; i < basis_degrees.size(); ++i) + { + basis_degrees_as_array[i] = basis_degrees[i]; + } + } + else + { + set_error_string("Unable to allocate memory!"); + } + } + catch (const Exception &e) + { + set_error_string(e.what()); + } + } + return basis_degrees_as_array; +} + +double *splinter_bspline_eval_row_major(splinter_obj_ptr bspline_ptr, double *xs, int x_len) +{ + double *retVal = nullptr; + + auto bspline = get_bspline(bspline_ptr); + if (bspline != nullptr) + { + try + { + size_t x_dim = bspline->get_dim_x(); + size_t y_dim = bspline->get_dim_y(); + size_t num_points = x_len / x_dim; + + retVal = (double *) malloc(sizeof(double) * num_points * y_dim); + for (size_t i = 0; i < num_points; i++) + { + auto xvec = get_vector(xs, x_dim); + // Underlying memory of vector is guaranteed to be contiguous + memcpy(&retVal[i*y_dim], bspline->eval(xvec).data(), sizeof(double) * y_dim); + xs += x_dim; + } + } + catch(const Exception &e) + { + set_error_string(e.what()); + } + } + + return retVal; +} + +double *splinter_bspline_eval_jacobian_row_major(splinter_obj_ptr bspline_ptr, double *x, int x_len) +{ + double *retVal = nullptr; + + auto bspline = get_bspline(bspline_ptr); + if (bspline != nullptr) + { + try + { + size_t num_variables = bspline->get_dim_x(); + size_t num_points = x_len / num_variables; + + retVal = (double *) malloc(sizeof(double) * num_variables * num_points); + for (size_t i = 0; i < num_points; ++i) + { + auto xvec = get_densevector(x, num_variables); + DenseMatrix jacobian = bspline->eval_jacobian(xvec); + + /* Copy jacobian from stack to heap */ + memcpy(retVal + i*num_variables, jacobian.data(), sizeof(double) * num_variables); + x += num_variables; + } + } + catch(const Exception &e) + { + set_error_string(e.what()); + } + } + + return retVal; +} + +double *splinter_bspline_eval_col_major(splinter_obj_ptr bspline_ptr, double *x, int x_len) +{ + double *retVal = nullptr; + + auto bspline = get_bspline(bspline_ptr); + if (bspline != nullptr) + { + double *row_major = nullptr; + try + { + row_major = get_row_major(x, bspline->get_dim_x(), x_len); + if (row_major == nullptr) + { + return nullptr; // Pass on the error message set by get_row_major + } + + retVal = splinter_bspline_eval_row_major(bspline, row_major, x_len); + } + catch(const Exception &e) + { + set_error_string(e.what()); + } + free(row_major); + } + + return retVal; +} + +double *splinter_bspline_eval_jacobian_col_major(splinter_obj_ptr bspline_ptr, double *x, int x_len) +{ + double *retVal = nullptr; + + auto bspline = get_bspline(bspline_ptr); + if (bspline != nullptr) + { + double *row_major = nullptr; + try + { + row_major = get_row_major(x, bspline->get_dim_x(), x_len); + if (row_major == nullptr) + { + return nullptr; // Pass on the error message set by get_row_major + } + + retVal = splinter_bspline_eval_jacobian_row_major(bspline, row_major, x_len); + } + catch(const Exception &e) + { + set_error_string(e.what()); + } + free(row_major); + } + + return retVal; +} + +int splinter_bspline_get_dim_x(splinter_obj_ptr bspline_ptr) +{ + int retVal = 1; + + auto bspline = get_bspline(bspline_ptr); + if (bspline != nullptr) + { + retVal = bspline->get_dim_x(); + } + + return retVal; +} + +int splinter_bspline_get_dim_y(splinter_obj_ptr bspline_ptr) +{ + int retVal = 1; + + auto bspline = get_bspline(bspline_ptr); + if (bspline != nullptr) + { + retVal = bspline->get_dim_y(); + } + + return retVal; +} + +void splinter_bspline_to_json(splinter_obj_ptr bspline_ptr, const char *filename) +{ + auto bspline = get_bspline(bspline_ptr); + if (bspline != nullptr) + { + try + { + bspline->to_json(filename); + } + catch(const Exception &e) + { + set_error_string(e.what()); + } + } +} + +splinter_obj_ptr splinter_bspline_from_json(const char *filename) +{ + splinter_obj_ptr loaded_bspline = nullptr; + + try + { + loaded_bspline = (splinter_obj_ptr) new BSpline(BSpline::from_json(filename)); + bsplines.insert(loaded_bspline); + } + catch (const Exception &e) + { + // Free the memory of the copy in case the exception was thrown by the insert + delete (BSpline *) loaded_bspline; + set_error_string(e.what()); + } + + return loaded_bspline; +} + +void splinter_bspline_delete(splinter_obj_ptr bspline_ptr) +{ + auto bspline = get_bspline(bspline_ptr); + + if (bspline != nullptr) + { + bsplines.erase(bspline_ptr); + delete bspline; + } +} + +void splinter_bspline_insert_knots(splinter_obj_ptr bspline_ptr, double tau, unsigned int dim, unsigned int multiplicity) +{ + auto bspline = get_bspline(bspline_ptr); + if (bspline != nullptr) + { + try + { + bspline->insert_knots(tau, dim, multiplicity); + } + catch (const Exception &e) + { + set_error_string(e.what()); + } + } +} + +void splinter_bspline_decompose_to_bezier_form(splinter_obj_ptr bspline_ptr) +{ + auto bspline = get_bspline(bspline_ptr); + if (bspline != nullptr) + { + try + { + bspline->decompose_to_bezier(); + } + catch (const Exception &e) + { + set_error_string(e.what()); + } + } +} + +splinter_obj_ptr splinter_bspline_copy(splinter_obj_ptr bspline_ptr) { + auto bspline = get_bspline(bspline_ptr); + splinter_obj_ptr copy = nullptr; + + if (bspline != nullptr) + { + try + { + copy = (splinter_obj_ptr) bspline->clone(); + bsplines.insert(copy); + } + catch (const Exception &e) + { + // Free the memory of the copy in case the exception was thrown by the insert + delete (BSpline *) copy; + set_error_string(e.what()); + } + } + return copy; +} + +splinter_obj_ptr splinter_bspline_fit(splinter_obj_ptr bspline_ptr, splinter_obj_ptr datatable_ptr, int smoothing, + double alpha, double *weights, int num_weights) +{ + auto bspline = get_bspline(bspline_ptr); + if (bspline == nullptr) + { + return nullptr; + } + + try + { + DataTable *dataTable = get_datatable(datatable_ptr); + auto _smoothing = resolve_smoothing(smoothing); + auto _weights = get_vector(weights, num_weights); + auto new_bspline = bspline->clone(); + new_bspline->fit(*dataTable, _smoothing, alpha, _weights); + bsplines.insert(new_bspline); + return new_bspline; + } + catch (const Exception &e) + { + set_error_string(e.what()); + } + + return nullptr; +} + +} // extern "C" diff --git a/splinter/src/cinterface/bspline_builders.cpp b/splinter/src/cinterface/bspline_builders.cpp new file mode 100644 index 0000000000..a28b711935 --- /dev/null +++ b/splinter/src/cinterface/bspline_builders.cpp @@ -0,0 +1,87 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include "bspline_builders.h" +#include "cinterface/cinterface.h" +#include "cinterface/utilities.h" + +using namespace SPLINTER; + +extern "C" +{ + +splinter_obj_ptr splinter_bspline_interpolator(splinter_obj_ptr datatable_ptr, int degree) +{ + splinter_obj_ptr bspline = nullptr; + DataTable *data_table = get_datatable(datatable_ptr); + try + { + bspline = (splinter_obj_ptr) bspline_interpolator(*data_table, degree).clone(); // TODO: unnecessary copy + bsplines.insert(bspline); + } + catch (const Exception &e) + { + set_error_string(e.what()); + } + + return bspline; +} + +splinter_obj_ptr splinter_bspline_smoother(splinter_obj_ptr datatable_ptr, int degree, int smoothing, double alpha, + double *weights, unsigned int num_weights) +{ + splinter_obj_ptr bspline = nullptr; + + try + { + DataTable *data_table = get_datatable(datatable_ptr); + auto _degree = static_cast(degree); + auto _weights = get_vector(weights, num_weights); + auto _smoothing = resolve_smoothing(smoothing); + + // TODO: Fix unnecessary copy + bspline = (splinter_obj_ptr) bspline_smoother(*data_table, _degree, _smoothing, alpha, _weights).clone(); + bsplines.insert(bspline); + } + catch (const Exception &e) + { + set_error_string(e.what()); + } + + return bspline; +} + +splinter_obj_ptr splinter_bspline_unfitted(splinter_obj_ptr datatable_ptr, unsigned int *degrees, + unsigned int num_degrees, int knot_spacing, + unsigned int *num_basis_functions, + unsigned int num_num_basis_functions) +{ + splinter_obj_ptr bspline = nullptr; + + try + { + DataTable *data_table = get_datatable(datatable_ptr); + auto _degrees = get_vector(degrees, num_degrees); + auto _knot_spacing = resolve_knot_spacing(knot_spacing); + auto _num_basis_functions = get_vector(num_basis_functions, num_num_basis_functions); + + // TODO: Fix unnecessary copy + bspline = (splinter_obj_ptr) bspline_unfitted(*data_table, _degrees, _knot_spacing, _num_basis_functions).clone(); + bsplines.insert(bspline); + } + catch (const Exception &e) + { + set_error_string(e.what()); + } + + return bspline; + +} + +} // extern "C" diff --git a/splinter/src/cinterface/cinterface.cpp b/splinter/src/cinterface/cinterface.cpp new file mode 100644 index 0000000000..5c33c38ee5 --- /dev/null +++ b/splinter/src/cinterface/cinterface.cpp @@ -0,0 +1,28 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include "cinterface/cinterface.h" +#include "cinterface/utilities.h" + +extern "C" +{ + +int splinter_get_error() +{ + int temp = SPLINTER::splinter_last_func_call_error; + SPLINTER::splinter_last_func_call_error = 0; + return temp; +} + +const char *splinter_get_error_string() +{ + return SPLINTER::splinter_error_string; +} + +} // extern "C" diff --git a/splinter/src/cinterface/data_table.cpp b/splinter/src/cinterface/data_table.cpp new file mode 100644 index 0000000000..4526710d19 --- /dev/null +++ b/splinter/src/cinterface/data_table.cpp @@ -0,0 +1,166 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include "cinterface/cinterface.h" +#include "cinterface/utilities.h" +#include "data_table.h" + +// Used for printing debug info to files when the library is loaded from eg. Python +#ifndef NDEBUG +# include +#endif + +using namespace SPLINTER; + +extern "C" +{ + +/* DataTable constructor */ +splinter_obj_ptr splinter_datatable_init() +{ + splinter_obj_ptr dataTable = (splinter_obj_ptr) new DataTable(); + + datatables.insert(dataTable); + + return dataTable; +} + +void splinter_datatable_add_samples_row_major(splinter_obj_ptr datatable_ptr, + double *xs, int x_dim, + double *ys, int y_dim, + int n_samples) +{ + auto dataTable = get_datatable(datatable_ptr); + if (dataTable != nullptr) + { + try + { + std::vector x_vec(x_dim, 0); + std::vector y_vec(y_dim, 0); + + for (int i = 0; i < n_samples; ++i) + { + // Vectors have been initialised to appropriate sizes, so this should be safe + memcpy(x_vec.data(), &xs[x_dim*i], sizeof(double) * x_dim); + memcpy(y_vec.data(), &ys[y_dim*i], sizeof(double) * y_dim); + + dataTable->add_sample(x_vec, y_vec); + } + } + catch(const Exception &e) + { + set_error_string(e.what()); + } + } +} + +void splinter_datatable_add_samples_col_major(splinter_obj_ptr datatable_ptr, double *x, int n_samples, int x_dim) +{ + auto dataTable = get_datatable(datatable_ptr); + if (dataTable != nullptr) + { + try + { + std::vector vec(x_dim, 0); + for (int i = 0; i < n_samples; ++i) + { + for (int j = 0; j < x_dim; ++j) + { + vec.at(j) = x[i + j * n_samples]; + } + + dataTable->add_sample(vec, x[i + x_dim * n_samples]); + } + } + catch(const Exception &e) + { + set_error_string(e.what()); + } + } +} + +int splinter_datatable_get_dim_x(splinter_obj_ptr datatable_ptr) +{ + auto dataTable = get_datatable(datatable_ptr); + if (dataTable != nullptr) + { + return (int) dataTable->get_dim_x(); + } + + return 0; +} + +int splinter_datatable_get_dim_y(splinter_obj_ptr datatable_ptr) +{ + auto dataTable = get_datatable(datatable_ptr); + if (dataTable != nullptr) + { + return (int) dataTable->get_dim_y(); + } + + return 0; +} + +int splinter_datatable_get_num_samples(splinter_obj_ptr datatable_ptr) +{ + auto dataTable = get_datatable(datatable_ptr); + if (dataTable != nullptr) + { + return dataTable->get_num_samples(); + } + + return 0; +} + +void splinter_datatable_to_json(splinter_obj_ptr datatable_ptr, const char *filename) +{ + auto datatable = get_datatable(datatable_ptr); + if (datatable != nullptr) + { + try + { + datatable->to_json(filename); + } + catch(const Exception &e) + { + set_error_string(e.what()); + } + } +} + +splinter_obj_ptr splinter_datatable_from_json(const char *filename) +{ + splinter_obj_ptr loaded_datatable = nullptr; + + try + { + loaded_datatable = (splinter_obj_ptr) new DataTable(DataTable::from_json(filename)); + datatables.insert(loaded_datatable); + } + catch (const Exception &e) + { + // Free the memory of the copy in case the exception was thrown by the insert + delete (DataTable *) loaded_datatable; + set_error_string(e.what()); + } + + return loaded_datatable; +} + +void splinter_datatable_delete(splinter_obj_ptr datatable_ptr) +{ + auto dataTable = get_datatable(datatable_ptr); + if (dataTable != nullptr) + { + datatables.erase(datatable_ptr); + delete dataTable; + } +} + +} // extern "C" diff --git a/splinter/src/cinterface/utilities.cpp b/splinter/src/cinterface/utilities.cpp new file mode 100644 index 0000000000..cc7a2ca6f2 --- /dev/null +++ b/splinter/src/cinterface/utilities.cpp @@ -0,0 +1,134 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include +#include "cinterface/utilities.h" + +namespace SPLINTER +{ + +std::set datatables = std::set(); +std::set bsplines = std::set(); + +// 1 if the last function call caused an error, 0 else +int splinter_last_func_call_error = 0; + +const char *splinter_error_string = "No error."; + +void set_error_string(const char *new_error_string) +{ + splinter_error_string = new_error_string; + splinter_last_func_call_error = 1; +} + +/* Cast the splinter_obj_ptr to a DataTable * */ +DataTable *get_datatable(splinter_obj_ptr datatable_ptr) +{ + if (datatables.count(datatable_ptr) > 0) + { + return static_cast(datatable_ptr); + } + + set_error_string("Invalid reference to DataTable: Maybe it has been deleted?"); + + return nullptr; +} + +/* Cast the splinter_obj_ptr to a BSpline * */ +BSpline *get_bspline(splinter_obj_ptr bspline_ptr) +{ + if (bsplines.count(bspline_ptr) > 0) + { + return static_cast(bspline_ptr); + } + + set_error_string("Invalid reference to BSpline: Maybe it has been deleted?"); + + return nullptr; +} + +/** + * Convert from column major to row major with point_dim number of columns. + * + * @param col_major Column major data + * @param point_dim Dimension of each point (= number of columns) + * @return col_major data stored row major. + */ +double *get_row_major(double *col_major, size_t point_dim, size_t x_len) +{ + if (point_dim == 0) + { + set_error_string("Dimension of x should be larger than 0!"); + return nullptr; + } + + double *row_major = (double *) malloc(sizeof(double) * x_len); + if(row_major == nullptr) + { + set_error_string("Out of memory!"); + return nullptr; + } + + size_t num_points = x_len / point_dim; + for (size_t i = 0; i < x_len; ++i) + { + size_t row_num = i / point_dim; // Intentional integer division + size_t col_num = i % point_dim; + row_major[i] = col_major[col_num * num_points + row_num]; + } + + return row_major; +} + +/** + * Resolve type of smoothing (see BSpline::Smoothing) + * @param smoothing as integer + * @return Smoothing + */ +BSpline::Smoothing resolve_smoothing(int smoothing) +{ + switch (smoothing) + { + case 0: + return BSpline::Smoothing::NONE; + case 1: + return BSpline::Smoothing::IDENTITY; + case 2: + return BSpline::Smoothing::PSPLINE; + default: + set_error_string("Error: Invalid smoothing type!"); + return BSpline::Smoothing::NONE; + } +} + +/** + * Resolve knot spacing type (see KnotSpacing in knot_builders.h) + * @param knot_spacing knot spacing as integer + * @return KnotSpacing + */ +KnotSpacing resolve_knot_spacing(int knot_spacing) +{ + switch (knot_spacing) + { + case 0: + return KnotSpacing::EXPERIMENTAL; + case 1: + return KnotSpacing::AS_SAMPLED; + case 2: + return KnotSpacing::EQUIDISTANT_CLAMPED; + case 3: + return KnotSpacing::EQUIDISTANT; + default: + set_error_string("Error: Invalid knot spacing!"); + return KnotSpacing::AS_SAMPLED; + } +} + + +} // namespace SPLINTER diff --git a/splinter/src/data_point.cpp b/splinter/src/data_point.cpp new file mode 100644 index 0000000000..89702d4527 --- /dev/null +++ b/splinter/src/data_point.cpp @@ -0,0 +1,58 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include "data_point.h" + +namespace SPLINTER +{ + +DataPoint::DataPoint(double x, double y) +{ + set_data(std::vector(1, x), + std::vector(1, y)); +} + +DataPoint::DataPoint(const std::vector &x, double y) +{ + set_data(x, std::vector(1, y)); +} + +DataPoint::DataPoint(double x, const std::vector &y) +{ + set_data(std::vector(1, x), y); +} + +DataPoint::DataPoint(const std::vector &x, const std::vector &y) +{ + set_data(x, y); +} + +void DataPoint::set_data(const std::vector &x, const std::vector &y) +{ + this->x = x; + this->y = y; +} + +bool DataPoint::operator<(const DataPoint &rhs) const +{ + if (this->get_dim_x() != rhs.get_dim_x()) + throw Exception("DataPoint::operator<: Cannot compare data points of different dimensions"); + + for (unsigned int i = 0; i < this->get_dim_x(); i++) + { + if (x.at(i) < rhs.get_x().at(i)) + return true; + else if (x.at(i) > rhs.get_x().at(i)) + return false; + } + + return false; +} + +} // namespace SPLINTER diff --git a/splinter/src/data_table.cpp b/splinter/src/data_table.cpp new file mode 100644 index 0000000000..530ecaad65 --- /dev/null +++ b/splinter/src/data_table.cpp @@ -0,0 +1,131 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include "data_table.h" +#include +#include +#include +#include +#include +#include + + +namespace SPLINTER +{ + +// TODO: add return value (iterator) +void DataTable::add_sample(const DataPoint &sample) +{ + if (get_num_samples() == 0) { + _dim_x = sample.get_dim_x(); + _dim_y = sample.get_dim_y(); + } + + if (sample.get_dim_x() != _dim_x || sample.get_dim_y() != _dim_y) { + throw Exception("DataTable::add_sample: Dimension of new sample is inconsistent with previous samples!"); + } + + samples.emplace_back(sample); +} + +void DataTable::add_sample(std::initializer_list samples) +{ + for (auto& sample : samples) + { + add_sample(sample); + } +} + +/** + * Get table of samples x-values: i.e. table[i][j] is the value of input i at sample j + */ +std::vector> DataTable::get_table_x() const +{ + std::vector> table(_dim_x, std::vector(get_num_samples())); + + unsigned int i = 0; + for (auto &sample : samples) { + auto x = sample.get_x(); + for (unsigned int j = 0; j < _dim_x; j++) + table.at(j).at(i) = x.at(j); + i++; + } + + return table; +} + +/** + * Get table of sampled y-values: i.e. table[i][j] is the value of output i at sample j + */ +std::vector> DataTable::get_table_y() const +{ + std::vector> table(_dim_y, std::vector(get_num_samples())); + unsigned int i = 0; + for (const auto &sample : samples) { + auto y = sample.get_y(); + for (unsigned int j = 0; j < _dim_y; ++j) + table.at(j).at(i) = y.at(j); + i++; + } + + return table; +} + +/** + * Check if grid is complete + */ +bool DataTable::is_grid_complete() const +{ + // Return true if there are no samples (ie. the grid is empty) + if (get_num_samples() == 0) + { + return true; + } + + // Construct grid + std::vector> grid; + + for (unsigned int i = 0; i < get_dim_x(); i++) + { + grid.emplace_back(std::set()); + } + + for (const auto &sample : samples) + { + for (unsigned int i = 0; i < get_dim_x(); i++) + { + grid.at(i).insert(sample.get_x().at(i)); + } + } + + // Compute number of grid points + unsigned int num_grid_points = 1; + for (auto &variable : grid) + { + num_grid_points *= variable.size(); + } + + // Check that there is a sample at every grid point. + // First, we count the number of unique sample points using a multiset (uniqueness is based on x-values). + // If the grid is fully sampled, this number must be equal to the number of grid points. + std::multiset unique_samples; + for (const auto &sample : samples) + { + // Check if the sample has been added already + if (unique_samples.count(sample) == 0) + { + unique_samples.insert(sample); + } + } + + return unique_samples.size() == num_grid_points; + +} + +} // namespace SPLINTER diff --git a/splinter/src/function.cpp b/splinter/src/function.cpp new file mode 100644 index 0000000000..c8ff85e93a --- /dev/null +++ b/splinter/src/function.cpp @@ -0,0 +1,63 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include +#include "utilities.h" + +namespace SPLINTER +{ + +DenseVector Function::eval(const DenseVector &x) const { + return std_to_eig_vec(eval(eig_to_std_vec(x))); +} + +std::vector> Function::eval_jacobian(const std::vector &x) const +{ + auto eig_x = std_to_eig_vec(x); + + return eig_to_std_mat(eval_jacobian(eig_x)); +} + +DenseMatrix Function::eval_jacobian(const DenseVector &x) const +{ + return central_difference(x); +} + +DenseMatrix Function::central_difference(const DenseVector &x) const +{ + DenseMatrix jacobian(dim_y, dim_x); + + double h = 1e-6; // perturbation step size + double h_forward = 0.5*h; + double h_backward = 0.5*h; + + for (unsigned int i = 0; i < dim_x; ++i) + { + DenseVector x_forward(x); + x_forward(i) = x_forward(i) + h_forward; + + DenseVector x_backward(x); + x_backward(i) = x_backward(i) - h_backward; + + auto y_forward = eval(x_forward); + auto y_backward = eval(x_backward); + + for (unsigned int j = 0; j < dim_y; ++j) + jacobian(j, i) = (y_forward(j) - y_backward(j)) / (h_backward + h_forward); + } + + return jacobian; +} + +void Function::check_input(const DenseVector &x) const { + return check_input(eig_to_std_vec(x)); +} + + +} // namespace SPLINTER \ No newline at end of file diff --git a/splinter/src/json_parser.cpp b/splinter/src/json_parser.cpp new file mode 100644 index 0000000000..022bd80d9d --- /dev/null +++ b/splinter/src/json_parser.cpp @@ -0,0 +1,146 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include "json_parser.h" +#include "json.h" +#include "bspline.h" +#include "data_table.h" +#include "utilities.h" +#include "fstream" + + +namespace SPLINTER { + +void bspline_to_json(const BSpline &bspline, const std::string &filename) +{ + std::ofstream ofs(filename); + nlohmann::json json; + + auto dim_x = bspline.get_dim_x(); + auto dim_y = bspline.get_dim_y(); + auto control_points = eig_to_std_mat(bspline.get_control_points().transpose()); + auto knot_vectors = bspline.get_knot_vectors(); + auto degrees = bspline.get_basis_degrees(); + + json["dim_x"] = dim_x; + json["dim_y"] = dim_y; + json["degrees"] = degrees; + + for (unsigned int i = 0; i < dim_x; ++i) { + std::string kv_str = "knot_vector_" + std::to_string(i); + json[kv_str] = knot_vectors.at(i); + } + + for (unsigned int i = 0; i < dim_y; ++i) { + std::string cp_str = "control_points_" + std::to_string(i); + json[cp_str] = control_points.at(i); + } + + ofs << json; +} + +BSpline bspline_from_json(const std::string &filename) +{ + std::ifstream ifs(filename); + nlohmann::json json; + ifs >> json; + + unsigned int dim_x = json["dim_x"]; + unsigned int dim_y = json["dim_y"]; + + std::vector> control_points_as_read; + std::vector> control_points; + std::vector> knot_vectors; + std::vector degrees; + + auto deg = json["degrees"]; + for (auto &it : deg) + degrees.push_back(it); + + for (unsigned int i = 0; i < dim_y; ++i) { + std::vector cp; + std::string e = "control_points_" + std::to_string(i); + auto c = json[e]; + for (auto &it : c) + cp.push_back(it); + control_points_as_read.push_back(cp); + } + + // Create list of dim_y-dimensional control points + for (unsigned int i = 0; i < control_points_as_read.at(0).size(); ++i) { + std::vector cp; + for (unsigned int j = 0; j < dim_y; ++j) { + auto cp_ij = control_points_as_read.at(j).at(i); + cp.push_back(cp_ij); + } + control_points.push_back(cp); + } + + for (unsigned int i = 0; i < dim_x; ++i) { + std::vector knots; + std::string e = "knot_vector_" + std::to_string(i); + auto k = json[e]; + for (auto &it : k) + knots.push_back(it); + knot_vectors.push_back(knots); + } + + return BSpline(degrees, knot_vectors, control_points); +} + +void datatable_to_json(const DataTable &data, const std::string &filename) +{ + std::ofstream ofs(filename); + nlohmann::json json; + + auto num_samples = data.get_num_samples(); + auto samples = data.get_samples(); + + json["num_samples"] = num_samples; + + unsigned int i = 0; + for (const auto &sample : samples) { + std::string str_x = "x_" + std::to_string(i); + std::string str_y = "y_" + std::to_string(i); + json[str_x] = sample.get_x(); + json[str_y] = sample.get_y(); + i++; + } + + ofs << json; +} + +DataTable datatable_from_json(const std::string &filename) +{ + std::ifstream ifs(filename); + nlohmann::json json; + ifs >> json; + + unsigned int num_samples = json["num_samples"]; + + auto data_table = DataTable(); + + for (unsigned int i = 0; i < num_samples; ++i) { + std::vector x; + std::vector y; + std::string str_x = "x_" + std::to_string(i); + std::string str_y = "y_" + std::to_string(i); + auto x_read = json[str_x]; + auto y_read = json[str_y]; + for (auto &it_x : x_read) + x.push_back(it_x); + for (auto &it_y : y_read) + y.push_back(it_y); + data_table.add_sample(x, y); + } + + return data_table; +} + +} // namespace SPLINTER \ No newline at end of file diff --git a/splinter/src/knot_builders.cpp b/splinter/src/knot_builders.cpp new file mode 100644 index 0000000000..d8758e3dc5 --- /dev/null +++ b/splinter/src/knot_builders.cpp @@ -0,0 +1,213 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include +#include +#include + + +namespace SPLINTER +{ + +// Compute all knot vectors from sample data +std::vector> build_knot_vectors(const DataTable &data, const std::vector °rees) +{ + auto num_basis_functions = std::vector(data.get_dim_x(), 10); // Not used when knot spacing is AS_SAMPLED + return build_knot_vectors(data, degrees, KnotSpacing::AS_SAMPLED, num_basis_functions); +} + +// Compute all knot vectors from sample data +std::vector> build_knot_vectors(const DataTable &data, + const std::vector °rees, + KnotSpacing knot_spacing, + const std::vector &num_basis_functions) +{ + auto dim_x = data.get_dim_x(); + + if (dim_x != degrees.size() || dim_x != num_basis_functions.size()) + throw Exception("BSpline::Builder::build_knot_vectors: Inconsistent sizes on input vectors."); + + std::vector> grid = data.get_table_x(); + + std::vector> knot_vectors; + + for (unsigned int i = 0; i < dim_x; ++i) + { + // Compute knot vector + auto knot_vector = build_knot_vector(grid.at(i), degrees.at(i), num_basis_functions.at(i), knot_spacing); + knot_vectors.push_back(knot_vector); + } + + return knot_vectors; +} + +// Compute a single knot vector from sample grid and degree +std::vector build_knot_vector(const std::vector &values, unsigned int degree, + unsigned int num_basis_functions, KnotSpacing knot_spacing) +{ + switch (knot_spacing) + { + case KnotSpacing::EXPERIMENTAL: + return knot_vector_expanded_equidistant(values, degree, num_basis_functions); + case KnotSpacing::AS_SAMPLED: + return knot_vector_moving_average(values, degree); + case KnotSpacing::EQUIDISTANT_CLAMPED: + return knot_vector_equidistant_clamped(values, degree, num_basis_functions); + case KnotSpacing::EQUIDISTANT: + return knot_vector_equidistant(values, degree, num_basis_functions); + default: + return knot_vector_moving_average(values, degree); + } +} + +/* +* Automatic construction of (p+1)-regular knot vector using moving average. +* +* Requirement: +* Knot vector should be of size n+p+1. +* End knots are should be repeated p+1 times. +* +* Computed sizes: +* n+2*(p) = n + p + 1 + (p - 1) +* k = (p - 1) values must be removed from sample vector. +* w = k + 3 window size in moving average +* +* Algorithm: +* 1) compute n - k values using moving average with window size w +* 2) repeat first and last value p + 1 times +* +* The resulting knot vector has n - k + 2*p = n + p + 1 knots. +* +* NOTE: +* For equidistant samples, the resulting knot vector is identically to +* the free end conditions knot vector used in cubic interpolation. +* That is, samples (a,b,c,d,e,f) produces the knot vector (a,a,a,a,c,d,f,f,f,f) for p = 3. +* For p = 1, (a,b,c,d,e,f) becomes (a,a,b,c,d,e,f,f). +* +* TODO: +* Does not work well when number of knots is << number of samples! For such cases +* almost all knots will lie close to the left samples. Try a bucket approach, where the +* samples are added to buckets and the knots computed as the average of these. +*/ +std::vector knot_vector_moving_average(const std::vector &values, unsigned int degree) +{ + // Sort and remove duplicates + std::vector unique = extract_unique_sorted(values); + + // Compute sizes + auto n = static_cast(unique.size()); + auto k = degree-1; // knots to remove + auto w = k + 3; // Window size + + // The minimum number of samples from which a free knot vector can be created + if (n < degree+1) + { + std::ostringstream e; + e << "knot_vector_moving_average: Only " << n + << " unique interpolation points are given. A minimum of degree+1 = " << degree+1 + << " unique points are required to build a B-spline basis of degree " << degree << "."; + throw Exception(e.str()); + } + + std::vector knots(n-k-2, 0); + + // Compute (n-k-2) interior knots using moving average + for (unsigned int i = 0; i < n-k-2; ++i) + { + double ma = 0; + for (unsigned int j = 0; j < w; ++j) + ma += unique.at(i+j); + + knots.at(i) = ma/w; + } + + // Repeat first knot p + 1 times (for interpolation of start point) + for (auto i = 0u; i < degree + 1; ++i) + knots.insert(knots.begin(), unique.front()); + + // Repeat last knot p + 1 times (for interpolation of end point) + for (auto i = 0u; i < degree + 1; ++i) + knots.insert(knots.end(), unique.back()); + + // Number of knots in a (p+1)-regular knot vector + //assert(knots.size() == unique.size() + degree + 1); + + return knots; +} + +std::vector knot_vector_equidistant_clamped(const std::vector &values, unsigned int degree, + unsigned int num_basis_functions) +{ + // Sort and remove duplicates + std::vector unique = extract_unique_sorted(values); + + // Compute sizes + auto n = static_cast(unique.size()); + if (num_basis_functions > 0) + n = num_basis_functions; + auto k = degree-1; // knots to remove + + // The minimum number of samples from which a free knot vector can be created + if (n < degree+1) + { + std::ostringstream e; + e << "knot_vector_equidistant_clamped: Only " << n + << " unique interpolation points are given. A minimum of degree+1 = " << degree+1 + << " unique points are required to build a B-spline basis of degree " << degree << "."; + throw Exception(e.str()); + } + + // Compute (n-k-2) equidistant interior knots + auto num_internal_knots = std::max(n-k-2, (unsigned int)0); + num_internal_knots = std::min((unsigned int)10, num_internal_knots); + std::vector knots = linspace(unique.front(), unique.back(), num_internal_knots); + + // Repeat first knot p + 1 times (for interpolation of start point) + for (auto i = 0u; i < degree; ++i) + knots.insert(knots.begin(), unique.front()); + + // Repeat last knot p + 1 times (for interpolation of end point) + for (auto i = 0u; i < degree; ++i) + knots.insert(knots.end(), unique.back()); + + // Number of knots in a (p+1)-regular knot vector + //assert(knots.size() == uniqueX.size() + degree + 1); + + return knots; +} + +std::vector knot_vector_equidistant(const std::vector &values, unsigned int degree, + unsigned int num_basis_functions) +{ + // Sort and remove duplicates + std::vector unique = extract_unique_sorted(values); + + // Build equidistant knots + unsigned int nk = num_basis_functions + degree + 1; + return linspace(unique.front(), unique.back(), nk); +} + +std::vector knot_vector_expanded_equidistant(const std::vector &values, unsigned int degree, + unsigned int num_basis_functions) +{ + // Sort and remove duplicates + std::vector unique = extract_unique_sorted(values); + + // Number of knots + unsigned int nk = num_basis_functions + degree + 1; + + // Expand each boundary by 10% of sample interval + double lb = unique.front(); + double ub = unique.back(); + double delta = ub - lb; + double expansion = 0.1; // A non-negative number + return linspace(unique.front() - expansion*delta, unique.back() + expansion*delta, nk); +} + +} // namespace SPLINTER diff --git a/splinter/src/knot_vector.cpp b/splinter/src/knot_vector.cpp new file mode 100644 index 0000000000..3815a6998c --- /dev/null +++ b/splinter/src/knot_vector.cpp @@ -0,0 +1,105 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include +#include + + +namespace SPLINTER +{ + +bool KnotVector::is_regular(unsigned int degree) const +{ +// // Check size +// if (size() < 2 * (degree + 1)) +// return false; + + // Check order + if (!is_nondecreasing()) + return false; + + // Check multiplicity of knots + for (auto it = cbegin(); it != cend(); ++it) + { + if (count(cbegin(), cend(), *it) > degree + 1) + return false; + } + + return true; +} + +bool KnotVector::is_refinement(const std::vector &refined_knots) const +{ + // Check size + if (refined_knots.size() < knots.size()) + return false; + + // Check that each element in knots occurs at least as many times in refined_knots + for (auto it = knots.cbegin() ; it != knots.cend(); ++it) + { + auto m_tau = count(knots.begin(), knots.end(), *it); + auto m_t = count(refined_knots.begin(), refined_knots.end(), *it); + if (m_t < m_tau) return false; + } + + // Check that range is not changed + if (knots.front() != refined_knots.front() || knots.back() != refined_knots.back()) + return false; + + return true; +} + +/** + * Check if end knots have multiplicity degree + 1 + * @param degree + * @return bool + */ +bool KnotVector::is_clamped(unsigned int degree) const +{ + // Check multiplicity of first knot + if (std::count(knots.begin(), knots.begin() + degree + 1, knots.front()) != degree + 1) + return false; + + // Check multiplicity of last knot + if (std::count(knots.end() - degree - 1, knots.end(), knots.back()) != degree + 1) + return false; + + return true; +} + +/** + * Finds index i such that knots.at(i) <= x < knots.at(i+1). + */ +unsigned int KnotVector::index_interval(double x) const +{ + if (!is_supported(x)) + throw Exception("KnotVector::index_interval: x outside knot support!"); + + // Find first knot that is larger than x + auto it = std::upper_bound(cbegin(), cend(), x); + + // Compute index + auto index = (it - knots.cbegin()) - 1; + + if (index < 0) + throw Exception("KnotVector::index_interval: computed negative index!"); + + return (unsigned int)index; +} + +bool operator==(const KnotVector &lhs, const KnotVector &rhs) { + auto is_equal = std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin()); + return is_equal && lhs.size() == rhs.size(); +} + +bool operator!=(const KnotVector &lhs, const KnotVector &rhs) { + return !(lhs == rhs); +} + +} // namespace SPLINTER diff --git a/splinter/mykroneckerproduct.cpp b/splinter/src/kronecker_product.cpp similarity index 84% rename from splinter/mykroneckerproduct.cpp rename to splinter/src/kronecker_product.cpp index 9e746ae660..31e513fa77 100644 --- a/splinter/mykroneckerproduct.cpp +++ b/splinter/src/kronecker_product.cpp @@ -7,7 +7,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "mykroneckerproduct.h" +#include "kronecker_product.h" #include "unsupported/Eigen/KroneckerProduct" namespace SPLINTER @@ -20,7 +20,7 @@ namespace SPLINTER * See: https://forum.kde.org/viewtopic.php?f=74&t=106955&p=309990&hilit=kronecker#p309990 * When Eigen update their implementation, and officially support it, we switch to that. */ -SparseMatrix myKroneckerProduct(const SparseMatrix &A, const SparseMatrix &B) +SparseMatrix my_kronecker_product(const SparseMatrix &A, const SparseMatrix &B) { SparseMatrix AB(A.rows()*B.rows(), A.cols()*B.cols()); @@ -39,14 +39,14 @@ SparseMatrix myKroneckerProduct(const SparseMatrix &A, const SparseMatrix &B) for (int jA = 0; jA < A.outerSize(); ++jA) { int nnz = 0; - for (SparseMatrix::InnerIterator itA(A,jA); itA; ++itA) nnz++; + for (SparseMatrix::InnerIterator itA(A, jA); itA; ++itA) nnz++; nnzA(jA) = nnz; } for (int jB = 0; jB < B.outerSize(); ++jB) { int nnz = 0; - for (SparseMatrix::InnerIterator itB(B,jB); itB; ++itB) nnz++; + for (SparseMatrix::InnerIterator itB(B, jB); itB; ++itB) nnz++; nnzB(jB) = nnz; } @@ -68,7 +68,7 @@ SparseMatrix myKroneckerProduct(const SparseMatrix &A, const SparseMatrix &B) // Compute Kronecker product for (int jA = 0; jA < A.outerSize(); ++jA) { - for (SparseMatrix::InnerIterator itA(A,jA); itA; ++itA) + for (SparseMatrix::InnerIterator itA(A, jA); itA; ++itA) { if (std::abs(itA.value()) > tolerance) { @@ -77,13 +77,13 @@ SparseMatrix myKroneckerProduct(const SparseMatrix &A, const SparseMatrix &B) for (int jB = 0; jB < B.outerSize(); ++jB) { - for (SparseMatrix::InnerIterator itB(B,jB); itB; ++itB) + for (SparseMatrix::InnerIterator itB(B, jB); itB; ++itB) { - if (std::abs(itA.value()*itB.value()) > tolerance) + if (std::abs(itB.value()) > tolerance) { int row = jrow + itB.row(); int col = jcol + itB.col(); - AB.insert(row,col) = itA.value()*itB.value(); + AB.insert(row, col) = itA.value()*itB.value(); } } } @@ -94,7 +94,7 @@ SparseMatrix myKroneckerProduct(const SparseMatrix &A, const SparseMatrix &B) return AB; } -SparseVector kroneckerProductVectors(const std::vector &vectors) +SparseVector kronecker_product_vectors(const std::vector &vectors) { // Create two temp matrices SparseMatrix temp1(1,1); @@ -120,7 +120,7 @@ SparseVector kroneckerProductVectors(const std::vector &vectors) return temp1; } -DenseVector kroneckerProductVectors(const std::vector &vectors) +DenseVector kronecker_product_vectors(const std::vector &vectors) { // Create two temp matrices DenseVector temp1(1); @@ -146,7 +146,7 @@ DenseVector kroneckerProductVectors(const std::vector &vectors) return temp1; } -SparseMatrix kroneckerProductMatrices(const std::vector &matrices) +SparseMatrix kronecker_product_matrices(const std::vector &matrices) { // Create two temp matrices SparseMatrix temp1(1,1); diff --git a/splinter/src/misc/Solve.h b/splinter/src/misc/Solve.h deleted file mode 100644 index 7f70d60afb..0000000000 --- a/splinter/src/misc/Solve.h +++ /dev/null @@ -1,76 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Benoit Jacob -// -// 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 - * - */ -template -struct traits > -{ - typedef typename DecompositionType::MatrixType MatrixType; - typedef Matrix ReturnType; -}; - -template struct solve_retval_base - : public ReturnByValue > -{ - typedef typename remove_all::type RhsNestedCleaned; - typedef _DecompositionType DecompositionType; - typedef ReturnByValue Base; - typedef typename Base::Index Index; - - 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; -}; - -} // end namespace internal - -#define EIGEN_MAKE_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::solve_retval_base Base; \ - using Base::dec; \ - using Base::rhs; \ - using Base::rows; \ - using Base::cols; \ - solve_retval(const DecompositionType& dec, const Rhs& rhs) \ - : Base(dec, rhs) {} - -} // end namespace Eigen - -#endif // EIGEN_MISC_SOLVE_H diff --git a/splinter/src/misc/SparseSolve.h b/splinter/src/misc/SparseSolve.h deleted file mode 100644 index 244bb8ec75..0000000000 --- a/splinter/src/misc/SparseSolve.h +++ /dev/null @@ -1,128 +0,0 @@ -// 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: - template - inline void defaultEvalTo(SparseMatrix& dst) const - { - // we process the sparse rhs per block of NbColsAtOnce columns temporarily stored into a dense matrix. - static const int NbColsAtOnce = 4; - int rhsCols = m_rhs.cols(); - int size = m_rhs.rows(); - Eigen::Matrix tmp(size,rhsCols); - Eigen::Matrix tmpX(size,rhsCols); - for(int k=0; k(rhsCols-k, NbColsAtOnce); - tmp.leftCols(actualCols) = m_rhs.middleCols(k,actualCols); - tmpX.leftCols(actualCols) = m_dec.solve(tmp.leftCols(actualCols)); - dst.middleCols(k,actualCols) = tmpX.leftCols(actualCols).sparseView(); - } - } - 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/splinter/src/misc/blas.h b/splinter/src/misc/blas.h deleted file mode 100644 index 6fce99ed5c..0000000000 --- a/splinter/src/misc/blas.h +++ /dev/null @@ -1,658 +0,0 @@ -#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/splinter/src/plugins/ArrayCwiseBinaryOps.h b/splinter/src/plugins/ArrayCwiseBinaryOps.h deleted file mode 100644 index 1951286f3a..0000000000 --- a/splinter/src/plugins/ArrayCwiseBinaryOps.h +++ /dev/null @@ -1,253 +0,0 @@ -/** \returns an expression of the coefficient wise product of \c *this and \a other - * - * \sa MatrixBase::cwiseProduct - */ -template -EIGEN_STRONG_INLINE const EIGEN_CWISE_PRODUCT_RETURN_TYPE(Derived,OtherDerived) -operator*(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const -{ - return EIGEN_CWISE_PRODUCT_RETURN_TYPE(Derived,OtherDerived)(derived(), other.derived()); -} - -/** \returns an expression of the coefficient wise quotient of \c *this and \a other - * - * \sa MatrixBase::cwiseQuotient - */ -template -EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const OtherDerived> -operator/(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 \c *this and \a other - * - * Example: \include Cwise_min.cpp - * Output: \verbinclude Cwise_min.out - * - * \sa max() - */ -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 CwiseNullaryOp, PlainObject> > -#ifdef EIGEN_PARSED_BY_DOXYGEN -min -#else -(min) -#endif -(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 - * Output: \verbinclude Cwise_max.out - * - * \sa min() - */ -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 CwiseNullaryOp, PlainObject> > -#ifdef EIGEN_PARSED_BY_DOXYGEN -max -#else -(max) -#endif -(const Scalar &other) const -{ - return (max)(Derived::PlainObject::Constant(rows(), cols(), other)); -} - - -#define EIGEN_MAKE_CWISE_COMP_OP(OP, COMPARATOR) \ -template \ -EIGEN_STRONG_INLINE const CwiseBinaryOp, const Derived, const OtherDerived> \ -OP(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const \ -{ \ - return CwiseBinaryOp, const Derived, const OtherDerived>(derived(), other.derived()); \ -}\ -typedef CwiseBinaryOp, const Derived, const CwiseNullaryOp, PlainObject> > Cmp ## COMPARATOR ## ReturnType; \ -typedef CwiseBinaryOp, const CwiseNullaryOp, PlainObject>, const Derived > RCmp ## COMPARATOR ## ReturnType; \ -EIGEN_STRONG_INLINE const Cmp ## COMPARATOR ## ReturnType \ -OP(const Scalar& s) const { \ - return this->OP(Derived::PlainObject::Constant(rows(), cols(), s)); \ -} \ -friend EIGEN_STRONG_INLINE const RCmp ## COMPARATOR ## ReturnType \ -OP(const Scalar& s, const Derived& d) { \ - return Derived::PlainObject::Constant(d.rows(), d.cols(), s).OP(d); \ -} - -#define EIGEN_MAKE_CWISE_COMP_R_OP(OP, R_OP, RCOMPARATOR) \ -template \ -EIGEN_STRONG_INLINE const CwiseBinaryOp, const OtherDerived, const Derived> \ -OP(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const \ -{ \ - return CwiseBinaryOp, const OtherDerived, const Derived>(other.derived(), derived()); \ -} \ -\ -inline const RCmp ## RCOMPARATOR ## ReturnType \ -OP(const Scalar& s) const { \ - return Derived::PlainObject::Constant(rows(), cols(), s).R_OP(*this); \ -} \ -friend inline const Cmp ## RCOMPARATOR ## ReturnType \ -OP(const Scalar& s, const Derived& d) { \ - return d.R_OP(Derived::PlainObject::Constant(d.rows(), d.cols(), s)); \ -} - - -/** \returns an expression of the coefficient-wise \< operator of *this and \a other - * - * Example: \include Cwise_less.cpp - * Output: \verbinclude Cwise_less.out - * - * \sa all(), any(), operator>(), operator<=() - */ -EIGEN_MAKE_CWISE_COMP_OP(operator<, LT) - -/** \returns an expression of the coefficient-wise \<= operator of *this and \a other - * - * Example: \include Cwise_less_equal.cpp - * Output: \verbinclude Cwise_less_equal.out - * - * \sa all(), any(), operator>=(), operator<() - */ -EIGEN_MAKE_CWISE_COMP_OP(operator<=, LE) - -/** \returns an expression of the coefficient-wise \> operator of *this and \a other - * - * Example: \include Cwise_greater.cpp - * Output: \verbinclude Cwise_greater.out - * - * \sa all(), any(), operator>=(), operator<() - */ -EIGEN_MAKE_CWISE_COMP_R_OP(operator>, operator<, LT) - -/** \returns an expression of the coefficient-wise \>= operator of *this and \a other - * - * Example: \include Cwise_greater_equal.cpp - * Output: \verbinclude Cwise_greater_equal.out - * - * \sa all(), any(), operator>(), operator<=() - */ -EIGEN_MAKE_CWISE_COMP_R_OP(operator>=, operator<=, LE) - -/** \returns an expression of the coefficient-wise == operator of *this and \a other - * - * \warning this performs an exact comparison, which is generally a bad idea with floating-point types. - * In order to check for equality between two vectors or matrices with floating-point coefficients, it is - * generally a far better idea to use a fuzzy comparison as provided by isApprox() and - * isMuchSmallerThan(). - * - * Example: \include Cwise_equal_equal.cpp - * Output: \verbinclude Cwise_equal_equal.out - * - * \sa all(), any(), isApprox(), isMuchSmallerThan() - */ -EIGEN_MAKE_CWISE_COMP_OP(operator==, EQ) - -/** \returns an expression of the coefficient-wise != operator of *this and \a other - * - * \warning this performs an exact comparison, which is generally a bad idea with floating-point types. - * In order to check for equality between two vectors or matrices with floating-point coefficients, it is - * generally a far better idea to use a fuzzy comparison as provided by isApprox() and - * isMuchSmallerThan(). - * - * Example: \include Cwise_not_equal.cpp - * Output: \verbinclude Cwise_not_equal.out - * - * \sa all(), any(), isApprox(), isMuchSmallerThan() - */ -EIGEN_MAKE_CWISE_COMP_OP(operator!=, NEQ) - -#undef EIGEN_MAKE_CWISE_COMP_OP -#undef EIGEN_MAKE_CWISE_COMP_R_OP - -// scalar addition - -/** \returns an expression of \c *this with each coeff incremented by the constant \a scalar - * - * Example: \include Cwise_plus.cpp - * Output: \verbinclude Cwise_plus.out - * - * \sa operator+=(), operator-() - */ -inline const CwiseUnaryOp, const Derived> -operator+(const Scalar& scalar) const -{ - return CwiseUnaryOp, const Derived>(derived(), internal::scalar_add_op(scalar)); -} - -friend inline const CwiseUnaryOp, const Derived> -operator+(const Scalar& scalar,const EIGEN_CURRENT_STORAGE_BASE_CLASS& other) -{ - return other + scalar; -} - -/** \returns an expression of \c *this with each coeff decremented by the constant \a scalar - * - * Example: \include Cwise_minus.cpp - * Output: \verbinclude Cwise_minus.out - * - * \sa operator+(), operator-=() - */ -inline const CwiseUnaryOp, const Derived> -operator-(const Scalar& scalar) const -{ - return *this + (-scalar); -} - -friend inline const CwiseUnaryOp, const CwiseUnaryOp, const Derived> > -operator-(const Scalar& scalar,const EIGEN_CURRENT_STORAGE_BASE_CLASS& other) -{ - 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/splinter/src/plugins/ArrayCwiseUnaryOps.h b/splinter/src/plugins/ArrayCwiseUnaryOps.h deleted file mode 100644 index 1c3ed3fcd7..0000000000 --- a/splinter/src/plugins/ArrayCwiseUnaryOps.h +++ /dev/null @@ -1,187 +0,0 @@ - - -/** \returns an expression of the coefficient-wise absolute value of \c *this - * - * Example: \include Cwise_abs.cpp - * Output: \verbinclude Cwise_abs.out - * - * \sa abs2() - */ -EIGEN_STRONG_INLINE const CwiseUnaryOp, const Derived> -abs() const -{ - return derived(); -} - -/** \returns an expression of the coefficient-wise squared absolute value of \c *this - * - * Example: \include Cwise_abs2.cpp - * Output: \verbinclude Cwise_abs2.out - * - * \sa abs(), square() - */ -EIGEN_STRONG_INLINE const CwiseUnaryOp, const Derived> -abs2() const -{ - return derived(); -} - -/** \returns an expression of the coefficient-wise exponential of *this. - * - * Example: \include Cwise_exp.cpp - * Output: \verbinclude Cwise_exp.out - * - * \sa pow(), log(), sin(), cos() - */ -inline const CwiseUnaryOp, const Derived> -exp() const -{ - return derived(); -} - -/** \returns an expression of the coefficient-wise logarithm of *this. - * - * Example: \include Cwise_log.cpp - * Output: \verbinclude Cwise_log.out - * - * \sa exp() - */ -inline const CwiseUnaryOp, const Derived> -log() const -{ - return derived(); -} - -/** \returns an expression of the coefficient-wise square root of *this. - * - * Example: \include Cwise_sqrt.cpp - * Output: \verbinclude Cwise_sqrt.out - * - * \sa pow(), square() - */ -inline const CwiseUnaryOp, const Derived> -sqrt() const -{ - return derived(); -} - -/** \returns an expression of the coefficient-wise cosine of *this. - * - * Example: \include Cwise_cos.cpp - * Output: \verbinclude Cwise_cos.out - * - * \sa sin(), acos() - */ -inline const CwiseUnaryOp, const Derived> -cos() const -{ - return derived(); -} - - -/** \returns an expression of the coefficient-wise sine of *this. - * - * Example: \include Cwise_sin.cpp - * Output: \verbinclude Cwise_sin.out - * - * \sa cos(), asin() - */ -inline const CwiseUnaryOp, const Derived> -sin() const -{ - return derived(); -} - -/** \returns an expression of the coefficient-wise arc cosine of *this. - * - * Example: \include Cwise_acos.cpp - * Output: \verbinclude Cwise_acos.out - * - * \sa cos(), asin() - */ -inline const CwiseUnaryOp, const Derived> -acos() const -{ - return derived(); -} - -/** \returns an expression of the coefficient-wise arc sine of *this. - * - * Example: \include Cwise_asin.cpp - * Output: \verbinclude Cwise_asin.out - * - * \sa sin(), acos() - */ -inline const CwiseUnaryOp, const Derived> -asin() const -{ - return derived(); -} - -/** \returns an expression of the coefficient-wise tan of *this. - * - * Example: \include Cwise_tan.cpp - * Output: \verbinclude Cwise_tan.out - * - * \sa cos(), sin() - */ -inline const CwiseUnaryOp, Derived> -tan() const -{ - return derived(); -} - - -/** \returns an expression of the coefficient-wise power of *this to the given exponent. - * - * Example: \include Cwise_pow.cpp - * Output: \verbinclude Cwise_pow.out - * - * \sa exp(), log() - */ -inline const CwiseUnaryOp, const Derived> -pow(const Scalar& exponent) const -{ - return CwiseUnaryOp, const Derived> - (derived(), internal::scalar_pow_op(exponent)); -} - - -/** \returns an expression of the coefficient-wise inverse of *this. - * - * Example: \include Cwise_inverse.cpp - * Output: \verbinclude Cwise_inverse.out - * - * \sa operator/(), operator*() - */ -inline const CwiseUnaryOp, const Derived> -inverse() const -{ - return derived(); -} - -/** \returns an expression of the coefficient-wise square of *this. - * - * Example: \include Cwise_square.cpp - * Output: \verbinclude Cwise_square.out - * - * \sa operator/(), operator*(), abs2() - */ -inline const CwiseUnaryOp, const Derived> -square() const -{ - return derived(); -} - -/** \returns an expression of the coefficient-wise cube of *this. - * - * Example: \include Cwise_cube.cpp - * Output: \verbinclude Cwise_cube.out - * - * \sa square(), pow() - */ -inline const CwiseUnaryOp, const Derived> -cube() const -{ - return derived(); -} diff --git a/splinter/src/plugins/BlockMethods.h b/splinter/src/plugins/BlockMethods.h deleted file mode 100644 index 2788251e0c..0000000000 --- a/splinter/src/plugins/BlockMethods.h +++ /dev/null @@ -1,935 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2010 Gael Guennebaud -// Copyright (C) 2006-2010 Benoit Jacob -// -// 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_PARSED_BY_DOXYGEN - -/** \internal expression type of a column */ -typedef Block::RowsAtCompileTime, 1, !IsRowMajor> ColXpr; -typedef const Block::RowsAtCompileTime, 1, !IsRowMajor> ConstColXpr; -/** \internal expression type of a row */ -typedef Block::ColsAtCompileTime, IsRowMajor> RowXpr; -typedef const Block::ColsAtCompileTime, IsRowMajor> ConstRowXpr; -/** \internal expression type of a block of whole columns */ -typedef Block::RowsAtCompileTime, Dynamic, !IsRowMajor> ColsBlockXpr; -typedef const Block::RowsAtCompileTime, Dynamic, !IsRowMajor> ConstColsBlockXpr; -/** \internal expression type of a block of whole rows */ -typedef Block::ColsAtCompileTime, IsRowMajor> RowsBlockXpr; -typedef const Block::ColsAtCompileTime, IsRowMajor> ConstRowsBlockXpr; -/** \internal expression type of a block of whole columns */ -template struct NColsBlockXpr { typedef Block::RowsAtCompileTime, N, !IsRowMajor> Type; }; -template struct ConstNColsBlockXpr { typedef const Block::RowsAtCompileTime, N, !IsRowMajor> Type; }; -/** \internal expression type of a block of whole rows */ -template struct NRowsBlockXpr { typedef Block::ColsAtCompileTime, IsRowMajor> Type; }; -template struct ConstNRowsBlockXpr { typedef const Block::ColsAtCompileTime, IsRowMajor> Type; }; - -typedef VectorBlock SegmentReturnType; -typedef const VectorBlock ConstSegmentReturnType; -template struct FixedSegmentReturnType { typedef VectorBlock Type; }; -template struct ConstFixedSegmentReturnType { typedef const VectorBlock Type; }; - -#endif // not EIGEN_PARSED_BY_DOXYGEN - -/** \returns a dynamic-size expression of a block in *this. - * - * \param startRow the first row in the block - * \param startCol the first column in the block - * \param blockRows the number of rows in the block - * \param blockCols the number of columns in the block - * - * Example: \include MatrixBase_block_int_int_int_int.cpp - * Output: \verbinclude MatrixBase_block_int_int_int_int.out - * - * \note Even though the returned expression has dynamic size, in the case - * when it is applied to a fixed-size matrix, it inherits a fixed maximal size, - * which means that evaluating it does not cause a dynamic memory allocation. - * - * \sa class Block, block(Index,Index) - */ -inline Block block(Index startRow, Index startCol, Index blockRows, Index blockCols) -{ - return Block(derived(), startRow, startCol, blockRows, blockCols); -} - -/** This is the const version of block(Index,Index,Index,Index). */ -inline const Block block(Index startRow, Index startCol, Index blockRows, Index blockCols) const -{ - return Block(derived(), startRow, startCol, blockRows, blockCols); -} - - - - -/** \returns a dynamic-size expression of a top-right corner of *this. - * - * \param cRows the number of rows in the corner - * \param cCols the number of columns in the corner - * - * Example: \include MatrixBase_topRightCorner_int_int.cpp - * Output: \verbinclude MatrixBase_topRightCorner_int_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -inline Block topRightCorner(Index cRows, Index cCols) -{ - return Block(derived(), 0, cols() - cCols, cRows, cCols); -} - -/** This is the const version of topRightCorner(Index, Index).*/ -inline const Block topRightCorner(Index cRows, Index cCols) const -{ - return Block(derived(), 0, cols() - cCols, cRows, cCols); -} - -/** \returns an expression of a fixed-size top-right corner of *this. - * - * \tparam CRows the number of rows in the corner - * \tparam CCols the number of columns in the corner - * - * Example: \include MatrixBase_template_int_int_topRightCorner.cpp - * Output: \verbinclude MatrixBase_template_int_int_topRightCorner.out - * - * \sa class Block, block(Index,Index) - */ -template -inline Block topRightCorner() -{ - return Block(derived(), 0, cols() - CCols); -} - -/** This is the const version of topRightCorner().*/ -template -inline const Block topRightCorner() const -{ - return Block(derived(), 0, cols() - CCols); -} - -/** \returns an expression of a top-right corner of *this. - * - * \tparam CRows number of rows in corner as specified at compile-time - * \tparam CCols number of columns in corner as specified at compile-time - * \param cRows number of rows in corner as specified at run-time - * \param cCols number of columns in corner as specified at run-time - * - * This function is mainly useful for corners where the number of rows is specified at compile-time - * and the number of columns is specified at run-time, or vice versa. The compile-time and run-time - * information should not contradict. In other words, \a cRows should equal \a CRows unless - * \a CRows is \a Dynamic, and the same for the number of columns. - * - * Example: \include MatrixBase_template_int_int_topRightCorner_int_int.cpp - * Output: \verbinclude MatrixBase_template_int_int_topRightCorner_int_int.out - * - * \sa class Block - */ -template -inline Block topRightCorner(Index cRows, Index cCols) -{ - return Block(derived(), 0, cols() - cCols, cRows, cCols); -} - -/** This is the const version of topRightCorner(Index, Index).*/ -template -inline const Block topRightCorner(Index cRows, Index cCols) const -{ - return Block(derived(), 0, cols() - cCols, cRows, cCols); -} - - - -/** \returns a dynamic-size expression of a top-left corner of *this. - * - * \param cRows the number of rows in the corner - * \param cCols the number of columns in the corner - * - * Example: \include MatrixBase_topLeftCorner_int_int.cpp - * Output: \verbinclude MatrixBase_topLeftCorner_int_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -inline Block topLeftCorner(Index cRows, Index cCols) -{ - return Block(derived(), 0, 0, cRows, cCols); -} - -/** This is the const version of topLeftCorner(Index, Index).*/ -inline const Block topLeftCorner(Index cRows, Index cCols) const -{ - return Block(derived(), 0, 0, cRows, cCols); -} - -/** \returns an expression of a fixed-size top-left corner of *this. - * - * The template parameters CRows and CCols are the number of rows and columns in the corner. - * - * Example: \include MatrixBase_template_int_int_topLeftCorner.cpp - * Output: \verbinclude MatrixBase_template_int_int_topLeftCorner.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -template -inline Block topLeftCorner() -{ - return Block(derived(), 0, 0); -} - -/** This is the const version of topLeftCorner().*/ -template -inline const Block topLeftCorner() const -{ - return Block(derived(), 0, 0); -} - -/** \returns an expression of a top-left corner of *this. - * - * \tparam CRows number of rows in corner as specified at compile-time - * \tparam CCols number of columns in corner as specified at compile-time - * \param cRows number of rows in corner as specified at run-time - * \param cCols number of columns in corner as specified at run-time - * - * This function is mainly useful for corners where the number of rows is specified at compile-time - * and the number of columns is specified at run-time, or vice versa. The compile-time and run-time - * information should not contradict. In other words, \a cRows should equal \a CRows unless - * \a CRows is \a Dynamic, and the same for the number of columns. - * - * Example: \include MatrixBase_template_int_int_topLeftCorner_int_int.cpp - * Output: \verbinclude MatrixBase_template_int_int_topLeftCorner_int_int.out - * - * \sa class Block - */ -template -inline Block topLeftCorner(Index cRows, Index cCols) -{ - return Block(derived(), 0, 0, cRows, cCols); -} - -/** This is the const version of topLeftCorner(Index, Index).*/ -template -inline const Block topLeftCorner(Index cRows, Index cCols) const -{ - return Block(derived(), 0, 0, cRows, cCols); -} - - - -/** \returns a dynamic-size expression of a bottom-right corner of *this. - * - * \param cRows the number of rows in the corner - * \param cCols the number of columns in the corner - * - * Example: \include MatrixBase_bottomRightCorner_int_int.cpp - * Output: \verbinclude MatrixBase_bottomRightCorner_int_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -inline Block bottomRightCorner(Index cRows, Index cCols) -{ - return Block(derived(), rows() - cRows, cols() - cCols, cRows, cCols); -} - -/** This is the const version of bottomRightCorner(Index, Index).*/ -inline const Block bottomRightCorner(Index cRows, Index cCols) const -{ - return Block(derived(), rows() - cRows, cols() - cCols, cRows, cCols); -} - -/** \returns an expression of a fixed-size bottom-right corner of *this. - * - * The template parameters CRows and CCols are the number of rows and columns in the corner. - * - * Example: \include MatrixBase_template_int_int_bottomRightCorner.cpp - * Output: \verbinclude MatrixBase_template_int_int_bottomRightCorner.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -template -inline Block bottomRightCorner() -{ - return Block(derived(), rows() - CRows, cols() - CCols); -} - -/** This is the const version of bottomRightCorner().*/ -template -inline const Block bottomRightCorner() const -{ - return Block(derived(), rows() - CRows, cols() - CCols); -} - -/** \returns an expression of a bottom-right corner of *this. - * - * \tparam CRows number of rows in corner as specified at compile-time - * \tparam CCols number of columns in corner as specified at compile-time - * \param cRows number of rows in corner as specified at run-time - * \param cCols number of columns in corner as specified at run-time - * - * This function is mainly useful for corners where the number of rows is specified at compile-time - * and the number of columns is specified at run-time, or vice versa. The compile-time and run-time - * information should not contradict. In other words, \a cRows should equal \a CRows unless - * \a CRows is \a Dynamic, and the same for the number of columns. - * - * Example: \include MatrixBase_template_int_int_bottomRightCorner_int_int.cpp - * Output: \verbinclude MatrixBase_template_int_int_bottomRightCorner_int_int.out - * - * \sa class Block - */ -template -inline Block bottomRightCorner(Index cRows, Index cCols) -{ - return Block(derived(), rows() - cRows, cols() - cCols, cRows, cCols); -} - -/** This is the const version of bottomRightCorner(Index, Index).*/ -template -inline const Block bottomRightCorner(Index cRows, Index cCols) const -{ - return Block(derived(), rows() - cRows, cols() - cCols, cRows, cCols); -} - - - -/** \returns a dynamic-size expression of a bottom-left corner of *this. - * - * \param cRows the number of rows in the corner - * \param cCols the number of columns in the corner - * - * Example: \include MatrixBase_bottomLeftCorner_int_int.cpp - * Output: \verbinclude MatrixBase_bottomLeftCorner_int_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -inline Block bottomLeftCorner(Index cRows, Index cCols) -{ - return Block(derived(), rows() - cRows, 0, cRows, cCols); -} - -/** This is the const version of bottomLeftCorner(Index, Index).*/ -inline const Block bottomLeftCorner(Index cRows, Index cCols) const -{ - return Block(derived(), rows() - cRows, 0, cRows, cCols); -} - -/** \returns an expression of a fixed-size bottom-left corner of *this. - * - * The template parameters CRows and CCols are the number of rows and columns in the corner. - * - * Example: \include MatrixBase_template_int_int_bottomLeftCorner.cpp - * Output: \verbinclude MatrixBase_template_int_int_bottomLeftCorner.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -template -inline Block bottomLeftCorner() -{ - return Block(derived(), rows() - CRows, 0); -} - -/** This is the const version of bottomLeftCorner().*/ -template -inline const Block bottomLeftCorner() const -{ - return Block(derived(), rows() - CRows, 0); -} - -/** \returns an expression of a bottom-left corner of *this. - * - * \tparam CRows number of rows in corner as specified at compile-time - * \tparam CCols number of columns in corner as specified at compile-time - * \param cRows number of rows in corner as specified at run-time - * \param cCols number of columns in corner as specified at run-time - * - * This function is mainly useful for corners where the number of rows is specified at compile-time - * and the number of columns is specified at run-time, or vice versa. The compile-time and run-time - * information should not contradict. In other words, \a cRows should equal \a CRows unless - * \a CRows is \a Dynamic, and the same for the number of columns. - * - * Example: \include MatrixBase_template_int_int_bottomLeftCorner_int_int.cpp - * Output: \verbinclude MatrixBase_template_int_int_bottomLeftCorner_int_int.out - * - * \sa class Block - */ -template -inline Block bottomLeftCorner(Index cRows, Index cCols) -{ - return Block(derived(), rows() - cRows, 0, cRows, cCols); -} - -/** This is the const version of bottomLeftCorner(Index, Index).*/ -template -inline const Block bottomLeftCorner(Index cRows, Index cCols) const -{ - return Block(derived(), rows() - cRows, 0, cRows, cCols); -} - - - -/** \returns a block consisting of the top rows of *this. - * - * \param n the number of rows in the block - * - * Example: \include MatrixBase_topRows_int.cpp - * Output: \verbinclude MatrixBase_topRows_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -inline RowsBlockXpr topRows(Index n) -{ - return RowsBlockXpr(derived(), 0, 0, n, cols()); -} - -/** This is the const version of topRows(Index).*/ -inline ConstRowsBlockXpr topRows(Index n) const -{ - return ConstRowsBlockXpr(derived(), 0, 0, n, cols()); -} - -/** \returns a block consisting of the top rows of *this. - * - * \tparam N the number of rows in the block as specified at compile-time - * \param n the number of rows in the block as specified at run-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include MatrixBase_template_int_topRows.cpp - * Output: \verbinclude MatrixBase_template_int_topRows.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -template -inline typename NRowsBlockXpr::Type topRows(Index n = N) -{ - return typename NRowsBlockXpr::Type(derived(), 0, 0, n, cols()); -} - -/** This is the const version of topRows().*/ -template -inline typename ConstNRowsBlockXpr::Type topRows(Index n = N) const -{ - return typename ConstNRowsBlockXpr::Type(derived(), 0, 0, n, cols()); -} - - - -/** \returns a block consisting of the bottom rows of *this. - * - * \param n the number of rows in the block - * - * Example: \include MatrixBase_bottomRows_int.cpp - * Output: \verbinclude MatrixBase_bottomRows_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -inline RowsBlockXpr bottomRows(Index n) -{ - return RowsBlockXpr(derived(), rows() - n, 0, n, cols()); -} - -/** This is the const version of bottomRows(Index).*/ -inline ConstRowsBlockXpr bottomRows(Index n) const -{ - return ConstRowsBlockXpr(derived(), rows() - n, 0, n, cols()); -} - -/** \returns a block consisting of the bottom rows of *this. - * - * \tparam N the number of rows in the block as specified at compile-time - * \param n the number of rows in the block as specified at run-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include MatrixBase_template_int_bottomRows.cpp - * Output: \verbinclude MatrixBase_template_int_bottomRows.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -template -inline typename NRowsBlockXpr::Type bottomRows(Index n = N) -{ - return typename NRowsBlockXpr::Type(derived(), rows() - n, 0, n, cols()); -} - -/** This is the const version of bottomRows().*/ -template -inline typename ConstNRowsBlockXpr::Type bottomRows(Index n = N) const -{ - return typename ConstNRowsBlockXpr::Type(derived(), rows() - n, 0, n, cols()); -} - - - -/** \returns a block consisting of a range of rows of *this. - * - * \param startRow the index of the first row in the block - * \param n the number of rows in the block - * - * Example: \include DenseBase_middleRows_int.cpp - * Output: \verbinclude DenseBase_middleRows_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -inline RowsBlockXpr middleRows(Index startRow, Index n) -{ - return RowsBlockXpr(derived(), startRow, 0, n, cols()); -} - -/** This is the const version of middleRows(Index,Index).*/ -inline ConstRowsBlockXpr middleRows(Index startRow, Index n) const -{ - return ConstRowsBlockXpr(derived(), startRow, 0, n, cols()); -} - -/** \returns a block consisting of a range of rows of *this. - * - * \tparam N the number of rows in the block as specified at compile-time - * \param startRow the index of the first row in the block - * \param n the number of rows in the block as specified at run-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include DenseBase_template_int_middleRows.cpp - * Output: \verbinclude DenseBase_template_int_middleRows.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -template -inline typename NRowsBlockXpr::Type middleRows(Index startRow, Index n = N) -{ - return typename NRowsBlockXpr::Type(derived(), startRow, 0, n, cols()); -} - -/** This is the const version of middleRows().*/ -template -inline typename ConstNRowsBlockXpr::Type middleRows(Index startRow, Index n = N) const -{ - return typename ConstNRowsBlockXpr::Type(derived(), startRow, 0, n, cols()); -} - - - -/** \returns a block consisting of the left columns of *this. - * - * \param n the number of columns in the block - * - * Example: \include MatrixBase_leftCols_int.cpp - * Output: \verbinclude MatrixBase_leftCols_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -inline ColsBlockXpr leftCols(Index n) -{ - return ColsBlockXpr(derived(), 0, 0, rows(), n); -} - -/** This is the const version of leftCols(Index).*/ -inline ConstColsBlockXpr leftCols(Index n) const -{ - return ConstColsBlockXpr(derived(), 0, 0, rows(), n); -} - -/** \returns a block consisting of the left columns of *this. - * - * \tparam N the number of columns in the block as specified at compile-time - * \param n the number of columns in the block as specified at run-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include MatrixBase_template_int_leftCols.cpp - * Output: \verbinclude MatrixBase_template_int_leftCols.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -template -inline typename NColsBlockXpr::Type leftCols(Index n = N) -{ - return typename NColsBlockXpr::Type(derived(), 0, 0, rows(), n); -} - -/** This is the const version of leftCols().*/ -template -inline typename ConstNColsBlockXpr::Type leftCols(Index n = N) const -{ - return typename ConstNColsBlockXpr::Type(derived(), 0, 0, rows(), n); -} - - - -/** \returns a block consisting of the right columns of *this. - * - * \param n the number of columns in the block - * - * Example: \include MatrixBase_rightCols_int.cpp - * Output: \verbinclude MatrixBase_rightCols_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -inline ColsBlockXpr rightCols(Index n) -{ - return ColsBlockXpr(derived(), 0, cols() - n, rows(), n); -} - -/** This is the const version of rightCols(Index).*/ -inline ConstColsBlockXpr rightCols(Index n) const -{ - return ConstColsBlockXpr(derived(), 0, cols() - n, rows(), n); -} - -/** \returns a block consisting of the right columns of *this. - * - * \tparam N the number of columns in the block as specified at compile-time - * \param n the number of columns in the block as specified at run-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include MatrixBase_template_int_rightCols.cpp - * Output: \verbinclude MatrixBase_template_int_rightCols.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -template -inline typename NColsBlockXpr::Type rightCols(Index n = N) -{ - return typename NColsBlockXpr::Type(derived(), 0, cols() - n, rows(), n); -} - -/** This is the const version of rightCols().*/ -template -inline typename ConstNColsBlockXpr::Type rightCols(Index n = N) const -{ - return typename ConstNColsBlockXpr::Type(derived(), 0, cols() - n, rows(), n); -} - - - -/** \returns a block consisting of a range of columns of *this. - * - * \param startCol the index of the first column in the block - * \param numCols the number of columns in the block - * - * Example: \include DenseBase_middleCols_int.cpp - * Output: \verbinclude DenseBase_middleCols_int.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -inline ColsBlockXpr middleCols(Index startCol, Index numCols) -{ - return ColsBlockXpr(derived(), 0, startCol, rows(), numCols); -} - -/** This is the const version of middleCols(Index,Index).*/ -inline ConstColsBlockXpr middleCols(Index startCol, Index numCols) const -{ - return ConstColsBlockXpr(derived(), 0, startCol, rows(), numCols); -} - -/** \returns a block consisting of a range of columns of *this. - * - * \tparam N the number of columns in the block as specified at compile-time - * \param startCol the index of the first column in the block - * \param n the number of columns in the block as specified at run-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include DenseBase_template_int_middleCols.cpp - * Output: \verbinclude DenseBase_template_int_middleCols.out - * - * \sa class Block, block(Index,Index,Index,Index) - */ -template -inline typename NColsBlockXpr::Type middleCols(Index startCol, Index n = N) -{ - return typename NColsBlockXpr::Type(derived(), 0, startCol, rows(), n); -} - -/** This is the const version of middleCols().*/ -template -inline typename ConstNColsBlockXpr::Type middleCols(Index startCol, Index n = N) const -{ - return typename ConstNColsBlockXpr::Type(derived(), 0, startCol, rows(), n); -} - - - -/** \returns a fixed-size expression of a block in *this. - * - * The template parameters \a BlockRows and \a BlockCols are the number of - * rows and columns in the block. - * - * \param startRow the first row in the block - * \param startCol the first column in the block - * - * Example: \include MatrixBase_block_int_int.cpp - * Output: \verbinclude MatrixBase_block_int_int.out - * - * \note since block is a templated member, the keyword template has to be used - * if the matrix type is also a template parameter: \code m.template block<3,3>(1,1); \endcode - * - * \sa class Block, block(Index,Index,Index,Index) - */ -template -inline Block block(Index startRow, Index startCol) -{ - return Block(derived(), startRow, startCol); -} - -/** This is the const version of block<>(Index, Index). */ -template -inline const Block block(Index startRow, Index startCol) const -{ - return Block(derived(), startRow, startCol); -} - -/** \returns an expression of a block in *this. - * - * \tparam BlockRows number of rows in block as specified at compile-time - * \tparam BlockCols number of columns in block as specified at compile-time - * \param startRow the first row in the block - * \param startCol the first column in the block - * \param blockRows number of rows in block as specified at run-time - * \param blockCols number of columns in block as specified at run-time - * - * This function is mainly useful for blocks where the number of rows is specified at compile-time - * and the number of columns is specified at run-time, or vice versa. The compile-time and run-time - * information should not contradict. In other words, \a blockRows should equal \a BlockRows unless - * \a BlockRows is \a Dynamic, and the same for the number of columns. - * - * Example: \include MatrixBase_template_int_int_block_int_int_int_int.cpp - * Output: \verbinclude MatrixBase_template_int_int_block_int_int_int_int.cpp - * - * \sa class Block, block(Index,Index,Index,Index) - */ -template -inline Block block(Index startRow, Index startCol, - Index blockRows, Index blockCols) -{ - return Block(derived(), startRow, startCol, blockRows, blockCols); -} - -/** This is the const version of block<>(Index, Index, Index, Index). */ -template -inline const Block block(Index startRow, Index startCol, - Index blockRows, Index blockCols) const -{ - return Block(derived(), startRow, startCol, blockRows, blockCols); -} - -/** \returns an expression of the \a i-th column of *this. Note that the numbering starts at 0. - * - * Example: \include MatrixBase_col.cpp - * Output: \verbinclude MatrixBase_col.out - * - * \sa row(), class Block */ -inline ColXpr col(Index i) -{ - return ColXpr(derived(), i); -} - -/** This is the const version of col(). */ -inline ConstColXpr col(Index i) const -{ - return ConstColXpr(derived(), i); -} - -/** \returns an expression of the \a i-th row of *this. Note that the numbering starts at 0. - * - * Example: \include MatrixBase_row.cpp - * Output: \verbinclude MatrixBase_row.out - * - * \sa col(), class Block */ -inline RowXpr row(Index i) -{ - return RowXpr(derived(), i); -} - -/** This is the const version of row(). */ -inline ConstRowXpr row(Index i) const -{ - return ConstRowXpr(derived(), i); -} - -/** \returns a dynamic-size expression of a segment (i.e. a vector block) in *this. - * - * \only_for_vectors - * - * \param start the first coefficient in the segment - * \param n the number of coefficients in the segment - * - * Example: \include MatrixBase_segment_int_int.cpp - * Output: \verbinclude MatrixBase_segment_int_int.out - * - * \note Even though the returned expression has dynamic size, in the case - * when it is applied to a fixed-size vector, it inherits a fixed maximal size, - * which means that evaluating it does not cause a dynamic memory allocation. - * - * \sa class Block, segment(Index) - */ -inline SegmentReturnType segment(Index start, Index n) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return SegmentReturnType(derived(), start, n); -} - - -/** This is the const version of segment(Index,Index).*/ -inline ConstSegmentReturnType segment(Index start, Index n) const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return ConstSegmentReturnType(derived(), start, n); -} - -/** \returns a dynamic-size expression of the first coefficients of *this. - * - * \only_for_vectors - * - * \param n the number of coefficients in the segment - * - * Example: \include MatrixBase_start_int.cpp - * Output: \verbinclude MatrixBase_start_int.out - * - * \note Even though the returned expression has dynamic size, in the case - * when it is applied to a fixed-size vector, it inherits a fixed maximal size, - * which means that evaluating it does not cause a dynamic memory allocation. - * - * \sa class Block, block(Index,Index) - */ -inline SegmentReturnType head(Index n) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return SegmentReturnType(derived(), 0, n); -} - -/** This is the const version of head(Index).*/ -inline ConstSegmentReturnType head(Index n) const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return ConstSegmentReturnType(derived(), 0, n); -} - -/** \returns a dynamic-size expression of the last coefficients of *this. - * - * \only_for_vectors - * - * \param n the number of coefficients in the segment - * - * Example: \include MatrixBase_end_int.cpp - * Output: \verbinclude MatrixBase_end_int.out - * - * \note Even though the returned expression has dynamic size, in the case - * when it is applied to a fixed-size vector, it inherits a fixed maximal size, - * which means that evaluating it does not cause a dynamic memory allocation. - * - * \sa class Block, block(Index,Index) - */ -inline SegmentReturnType tail(Index n) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return SegmentReturnType(derived(), this->size() - n, n); -} - -/** This is the const version of tail(Index).*/ -inline ConstSegmentReturnType tail(Index n) const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return ConstSegmentReturnType(derived(), this->size() - n, n); -} - -/** \returns a fixed-size expression of a segment (i.e. a vector block) in \c *this - * - * \only_for_vectors - * - * \tparam N the number of coefficients in the segment as specified at compile-time - * \param start the index of the first element in the segment - * \param n the number of coefficients in the segment as specified at compile-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include MatrixBase_template_int_segment.cpp - * Output: \verbinclude MatrixBase_template_int_segment.out - * - * \sa class Block - */ -template -inline typename FixedSegmentReturnType::Type segment(Index start, Index n = N) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return typename FixedSegmentReturnType::Type(derived(), start, n); -} - -/** This is the const version of segment(Index).*/ -template -inline typename ConstFixedSegmentReturnType::Type segment(Index start, Index n = N) const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return typename ConstFixedSegmentReturnType::Type(derived(), start, n); -} - -/** \returns a fixed-size expression of the first coefficients of *this. - * - * \only_for_vectors - * - * \tparam N the number of coefficients in the segment as specified at compile-time - * \param n the number of coefficients in the segment as specified at run-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include MatrixBase_template_int_start.cpp - * Output: \verbinclude MatrixBase_template_int_start.out - * - * \sa class Block - */ -template -inline typename FixedSegmentReturnType::Type head(Index n = N) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return typename FixedSegmentReturnType::Type(derived(), 0, n); -} - -/** This is the const version of head().*/ -template -inline typename ConstFixedSegmentReturnType::Type head(Index n = N) const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return typename ConstFixedSegmentReturnType::Type(derived(), 0, n); -} - -/** \returns a fixed-size expression of the last coefficients of *this. - * - * \only_for_vectors - * - * \tparam N the number of coefficients in the segment as specified at compile-time - * \param n the number of coefficients in the segment as specified at run-time - * - * The compile-time and run-time information should not contradict. In other words, - * \a n should equal \a N unless \a N is \a Dynamic. - * - * Example: \include MatrixBase_template_int_end.cpp - * Output: \verbinclude MatrixBase_template_int_end.out - * - * \sa class Block - */ -template -inline typename FixedSegmentReturnType::Type tail(Index n = N) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return typename FixedSegmentReturnType::Type(derived(), size() - n); -} - -/** This is the const version of tail.*/ -template -inline typename ConstFixedSegmentReturnType::Type tail(Index n = N) const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return typename ConstFixedSegmentReturnType::Type(derived(), size() - n); -} diff --git a/splinter/src/plugins/CommonCwiseBinaryOps.h b/splinter/src/plugins/CommonCwiseBinaryOps.h deleted file mode 100644 index 688d224408..0000000000 --- a/splinter/src/plugins/CommonCwiseBinaryOps.h +++ /dev/null @@ -1,46 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// 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. - -/** \returns an expression of the difference of \c *this and \a other - * - * \note If you want to substract a given scalar from all coefficients, see Cwise::operator-(). - * - * \sa class CwiseBinaryOp, operator-=() - */ -EIGEN_MAKE_CWISE_BINARY_OP(operator-,internal::scalar_difference_op) - -/** \returns an expression of the sum of \c *this and \a other - * - * \note If you want to add a given scalar to all coefficients, see Cwise::operator+(). - * - * \sa class CwiseBinaryOp, operator+=() - */ -EIGEN_MAKE_CWISE_BINARY_OP(operator+,internal::scalar_sum_op) - -/** \returns an expression of a custom coefficient-wise operator \a func of *this and \a other - * - * The template parameter \a CustomBinaryOp is the type of the functor - * of the custom operator (see class CwiseBinaryOp for an example) - * - * Here is an example illustrating the use of custom functors: - * \include class_CwiseBinaryOp.cpp - * Output: \verbinclude class_CwiseBinaryOp.out - * - * \sa class CwiseBinaryOp, operator+(), operator-(), cwiseProduct() - */ -template -EIGEN_STRONG_INLINE const CwiseBinaryOp -binaryExpr(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other, const CustomBinaryOp& func = CustomBinaryOp()) const -{ - return CwiseBinaryOp(derived(), other.derived(), func); -} - diff --git a/splinter/src/plugins/CommonCwiseUnaryOps.h b/splinter/src/plugins/CommonCwiseUnaryOps.h deleted file mode 100644 index 08e931aadd..0000000000 --- a/splinter/src/plugins/CommonCwiseUnaryOps.h +++ /dev/null @@ -1,172 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// 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. - -#ifndef EIGEN_PARSED_BY_DOXYGEN - -/** \internal Represents a scalar multiple of an expression */ -typedef CwiseUnaryOp, const Derived> ScalarMultipleReturnType; -/** \internal Represents a quotient of an expression by a scalar*/ -typedef CwiseUnaryOp, const Derived> ScalarQuotient1ReturnType; -/** \internal the return type of conjugate() */ -typedef typename internal::conditional::IsComplex, - const CwiseUnaryOp, const Derived>, - const Derived& - >::type ConjugateReturnType; -/** \internal the return type of real() const */ -typedef typename internal::conditional::IsComplex, - const CwiseUnaryOp, const Derived>, - const Derived& - >::type RealReturnType; -/** \internal the return type of real() */ -typedef typename internal::conditional::IsComplex, - CwiseUnaryView, Derived>, - Derived& - >::type NonConstRealReturnType; -/** \internal the return type of imag() const */ -typedef CwiseUnaryOp, const Derived> ImagReturnType; -/** \internal the return type of imag() */ -typedef CwiseUnaryView, Derived> NonConstImagReturnType; - -#endif // not EIGEN_PARSED_BY_DOXYGEN - -/** \returns an expression of the opposite of \c *this - */ -inline const CwiseUnaryOp::Scalar>, const Derived> -operator-() const { return derived(); } - - -/** \returns an expression of \c *this scaled by the scalar factor \a scalar */ -inline const ScalarMultipleReturnType -operator*(const Scalar& scalar) const -{ - return CwiseUnaryOp, const Derived> - (derived(), internal::scalar_multiple_op(scalar)); -} - -#ifdef EIGEN_PARSED_BY_DOXYGEN -const ScalarMultipleReturnType operator*(const RealScalar& scalar) const; -#endif - -/** \returns an expression of \c *this divided by the scalar value \a scalar */ -inline const CwiseUnaryOp::Scalar>, const Derived> -operator/(const Scalar& scalar) const -{ - return CwiseUnaryOp, const Derived> - (derived(), internal::scalar_quotient1_op(scalar)); -} - -/** Overloaded for efficient real matrix times complex scalar value */ -inline const CwiseUnaryOp >, const Derived> -operator*(const std::complex& scalar) const -{ - return CwiseUnaryOp >, const Derived> - (*static_cast(this), internal::scalar_multiple2_op >(scalar)); -} - -inline friend const ScalarMultipleReturnType -operator*(const Scalar& scalar, const StorageBaseType& matrix) -{ return matrix*scalar; } - -inline friend const CwiseUnaryOp >, const Derived> -operator*(const std::complex& scalar, const StorageBaseType& matrix) -{ return matrix*scalar; } - -/** \returns an expression of *this with the \a Scalar type casted to - * \a NewScalar. - * - * The template parameter \a NewScalar is the type we are casting the scalars to. - * - * \sa class CwiseUnaryOp - */ -template -typename internal::cast_return_type::Scalar, NewType>, const Derived> >::type -cast() const -{ - return derived(); -} - -/** \returns an expression of the complex conjugate of \c *this. - * - * \sa adjoint() */ -inline ConjugateReturnType -conjugate() const -{ - return ConjugateReturnType(derived()); -} - -/** \returns a read-only expression of the real part of \c *this. - * - * \sa imag() */ -inline RealReturnType -real() const { return derived(); } - -/** \returns an read-only expression of the imaginary part of \c *this. - * - * \sa real() */ -inline const ImagReturnType -imag() const { return derived(); } - -/** \brief Apply a unary operator coefficient-wise - * \param[in] func Functor implementing the unary operator - * \tparam CustomUnaryOp Type of \a func - * \returns An expression of a custom coefficient-wise unary operator \a func of *this - * - * The function \c ptr_fun() from the C++ standard library can be used to make functors out of normal functions. - * - * Example: - * \include class_CwiseUnaryOp_ptrfun.cpp - * Output: \verbinclude class_CwiseUnaryOp_ptrfun.out - * - * Genuine functors allow for more possibilities, for instance it may contain a state. - * - * Example: - * \include class_CwiseUnaryOp.cpp - * Output: \verbinclude class_CwiseUnaryOp.out - * - * \sa class CwiseUnaryOp, class CwiseBinaryOp - */ -template -inline const CwiseUnaryOp -unaryExpr(const CustomUnaryOp& func = CustomUnaryOp()) const -{ - return CwiseUnaryOp(derived(), func); -} - -/** \returns an expression of a custom coefficient-wise unary operator \a func of *this - * - * The template parameter \a CustomUnaryOp is the type of the functor - * of the custom unary operator. - * - * Example: - * \include class_CwiseUnaryOp.cpp - * Output: \verbinclude class_CwiseUnaryOp.out - * - * \sa class CwiseUnaryOp, class CwiseBinaryOp - */ -template -inline const CwiseUnaryView -unaryViewExpr(const CustomViewOp& func = CustomViewOp()) const -{ - return CwiseUnaryView(derived(), func); -} - -/** \returns a non const expression of the real part of \c *this. - * - * \sa imag() */ -inline NonConstRealReturnType -real() { return derived(); } - -/** \returns a non const expression of the imaginary part of \c *this. - * - * \sa real() */ -inline NonConstImagReturnType -imag() { return derived(); } diff --git a/splinter/src/plugins/MatrixCwiseUnaryOps.h b/splinter/src/plugins/MatrixCwiseUnaryOps.h deleted file mode 100644 index 8de10935d5..0000000000 --- a/splinter/src/plugins/MatrixCwiseUnaryOps.h +++ /dev/null @@ -1,52 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// 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. - -/** \returns an expression of the coefficient-wise absolute value of \c *this - * - * Example: \include MatrixBase_cwiseAbs.cpp - * Output: \verbinclude MatrixBase_cwiseAbs.out - * - * \sa cwiseAbs2() - */ -EIGEN_STRONG_INLINE const CwiseUnaryOp, const Derived> -cwiseAbs() const { return derived(); } - -/** \returns an expression of the coefficient-wise squared absolute value of \c *this - * - * Example: \include MatrixBase_cwiseAbs2.cpp - * Output: \verbinclude MatrixBase_cwiseAbs2.out - * - * \sa cwiseAbs() - */ -EIGEN_STRONG_INLINE const CwiseUnaryOp, const Derived> -cwiseAbs2() const { return derived(); } - -/** \returns an expression of the coefficient-wise square root of *this. - * - * Example: \include MatrixBase_cwiseSqrt.cpp - * Output: \verbinclude MatrixBase_cwiseSqrt.out - * - * \sa cwisePow(), cwiseSquare() - */ -inline const CwiseUnaryOp, const Derived> -cwiseSqrt() const { return derived(); } - -/** \returns an expression of the coefficient-wise inverse of *this. - * - * Example: \include MatrixBase_cwiseInverse.cpp - * Output: \verbinclude MatrixBase_cwiseInverse.out - * - * \sa cwiseProduct() - */ -inline const CwiseUnaryOp, const Derived> -cwiseInverse() const { return derived(); } - diff --git a/splinter/src/utilities.cpp b/splinter/src/utilities.cpp new file mode 100644 index 0000000000..6df29a774e --- /dev/null +++ b/splinter/src/utilities.cpp @@ -0,0 +1,109 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * 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/. +*/ + +#include "utilities.h" + +namespace SPLINTER +{ + +std::vector eig_to_std_vec(const DenseVector &vec) +{ + std::vector stdVec(vec.size()); + + for(size_t i = 0; i < (size_t) stdVec.size(); ++i) + stdVec.at(i) = vec(i); + + return stdVec; +} + +DenseVector std_to_eig_vec(const std::vector &vec) +{ + DenseVector eigVec(vec.size()); + eigVec.setZero(); + + for (size_t i = 0; i < vec.size(); ++i) + eigVec(i) = vec.at(i); + + return eigVec; +} + +std::vector> eig_to_std_mat(const DenseMatrix &mat) +{ + std::vector> vec(mat.rows()); + + for(size_t i = 0; i < (size_t) mat.rows(); ++i) + { + for(size_t j = 0; j < (size_t) mat.cols(); ++j) + { + vec.at(i).push_back(mat(i, j)); + } + } + + return vec; +} + +DenseMatrix std_to_eig_mat(const std::vector> &vec) +{ + size_t numRows = vec.size(); + size_t numCols = numRows > 0 ? vec.at(0).size() : 0; + + DenseMatrix mat(numRows, numCols); + + for(size_t i = 0; i < numRows; ++i) + { + for(size_t j = 0; j < numCols; ++j) + { + mat(i, j) = vec.at(i).at(j); + } + } + + return mat; +} + +std::vector linspace(double start, double stop, unsigned int num) +{ + std::vector ret; + double dx = 0; + if (num > 1) + dx = (stop - start)/(num-1); + for (unsigned int i = 0; i < num; ++i) + ret.push_back(start + i*dx); + return ret; +} + +std::vector extract_unique_sorted(const std::vector &values) +{ + // Sort and remove duplicates + std::vector unique(values); + std::sort(unique.begin(), unique.end()); + std::vector::iterator it = unique_copy(unique.begin(), unique.end(), unique.begin()); + unique.resize(distance(unique.begin(),it)); + return unique; +} + +std::vector> transpose_vec_vec(std::vector> x) +{ + std::vector> xt; + if (x.size() == 0) { + return xt; + } + size_t inner_dim = x.at(0).size(); + + for (unsigned int i = 0; i < inner_dim; ++i) { + std::vector inner; + for (unsigned int j = 0; j < x.size(); ++j) { + auto xji = x.at(j).at(i); + inner.push_back(xji); + } + xt.push_back(inner); + } + return xt; +} + +} // namespace SPLINTER diff --git a/splinter/thirdparty/Catch/Catch.h b/splinter/thirdparty/Catch/Catch.h new file mode 100644 index 0000000000..2d7b64ec12 --- /dev/null +++ b/splinter/thirdparty/Catch/Catch.h @@ -0,0 +1,9415 @@ +/* + * Catch v1.2.1 + * Generated: 2015-06-30 18:23:27.961086 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + +#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// #included from: internal/catch_suppress_warnings.h + +#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic ignored "-Wglobal-constructors" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wc99-extensions" +# pragma clang diagnostic ignored "-Wunused-variable" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# pragma clang diagnostic ignored "-Wswitch-enum" +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic ignored "-Wvariadic-macros" +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpadded" +#endif + +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +#endif + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// #included from: internal/catch_notimplemented_exception.h +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED + +// #included from: catch_common.h +#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED + +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) + +#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr +#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) + +#include +#include +#include + +// #included from: catch_compiler_capabilities.h +#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? +// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported + +// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 + +#ifdef __clang__ + +# if __has_feature(cxx_nullptr) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if __has_feature(cxx_noexcept) +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Borland +#ifdef __BORLANDC__ + +#endif // __BORLANDC__ + +//////////////////////////////////////////////////////////////////////////////// +// EDG +#ifdef __EDG_VERSION__ + +#endif // __EDG_VERSION__ + +//////////////////////////////////////////////////////////////////////////////// +// Digital Mars +#ifdef __DMC__ + +#endif // __DMC__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) ) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +// Use variadic macros if the compiler supports them +#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ + ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ + ( defined __GNUC__ && __GNUC__ >= 3 ) || \ + ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) + +#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if (__cplusplus >= 201103L) + +# define CATCH_CPP11_OR_GREATER + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# endif + +# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NULLPTR +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_IS_ENUM +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TUPLE +#endif +#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) +#define CATCH_CONFIG_VARIADIC_MACROS +#endif + +// noexcept support: +#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) +# define CATCH_NOEXCEPT noexcept +# define CATCH_NOEXCEPT_IS(x) noexcept(x) +#else +# define CATCH_NOEXCEPT throw() +# define CATCH_NOEXCEPT_IS(x) +#endif + +namespace Catch { + +class NonCopyable { +#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; +#else + NonCopyable( NonCopyable const& info ); + NonCopyable& operator = ( NonCopyable const& ); +#endif + +protected: + NonCopyable() {} + virtual ~NonCopyable(); +}; + +class SafeBool { +public: + typedef void (SafeBool::*type)() const; + + static type makeSafe( bool value ) { + return value ? &SafeBool::trueValue : 0; + } +private: + void trueValue() const {} +}; + +template +inline void deleteAll( ContainerT& container ) { + typename ContainerT::const_iterator it = container.begin(); + typename ContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete *it; +} +template +inline void deleteAllValues( AssociativeContainerT& container ) { + typename AssociativeContainerT::const_iterator it = container.begin(); + typename AssociativeContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete it->second; +} + +bool startsWith( std::string const& s, std::string const& prefix ); +bool endsWith( std::string const& s, std::string const& suffix ); +bool contains( std::string const& s, std::string const& infix ); +void toLowerInPlace( std::string& s ); +std::string toLower( std::string const& s ); +std::string trim( std::string const& str ); +bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + +struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; +}; + +struct SourceLineInfo { + + SourceLineInfo(); + SourceLineInfo( char const* _file, std::size_t _line ); + SourceLineInfo( SourceLineInfo const& other ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; +# endif + bool empty() const; + bool operator == ( SourceLineInfo const& other ) const; + bool operator < ( SourceLineInfo const& other ) const; + + std::string file; + std::size_t line; +}; + +std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + +// This is just here to avoid compiler warnings with macro constants and boolean literals +inline bool isTrue( bool value ){ return value; } +inline bool alwaysTrue() { return true; } +inline bool alwaysFalse() { return false; } + +void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + +// Use this in variadic streaming macros to allow +// >> +StreamEndStop +// as well as +// >> stuff +StreamEndStop +struct StreamEndStop { + std::string operator+() { + return std::string(); + } +}; +template +T const& operator + ( T const& value, StreamEndStop ) { + return value; +} +} + +#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) +#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); + +#include + +namespace Catch { + +class NotImplementedException : public std::exception +{ +public: + NotImplementedException( SourceLineInfo const& lineInfo ); + NotImplementedException( NotImplementedException const& ) {} + + virtual ~NotImplementedException() CATCH_NOEXCEPT {} + + virtual const char* what() const CATCH_NOEXCEPT; + +private: + std::string m_what; + SourceLineInfo m_lineInfo; +}; + +} // end namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) + +// #included from: internal/catch_context.h +#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED + +// #included from: catch_interfaces_generators.h +#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED + +#include + +namespace Catch { + +struct IGeneratorInfo { + virtual ~IGeneratorInfo(); + virtual bool moveNext() = 0; + virtual std::size_t getCurrentIndex() const = 0; +}; + +struct IGeneratorsForTest { + virtual ~IGeneratorsForTest(); + + virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; + virtual bool moveNext() = 0; +}; + +IGeneratorsForTest* createGeneratorsForTest(); + +} // end namespace Catch + +// #included from: catch_ptr.hpp +#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + +// An intrusive reference counting smart pointer. +// T must implement addRef() and release() methods +// typically implementing the IShared interface +template +class Ptr { +public: + Ptr() : m_p( NULL ){} + Ptr( T* p ) : m_p( p ){ + if( m_p ) + m_p->addRef(); + } + Ptr( Ptr const& other ) : m_p( other.m_p ){ + if( m_p ) + m_p->addRef(); + } + ~Ptr(){ + if( m_p ) + m_p->release(); + } + void reset() { + if( m_p ) + m_p->release(); + m_p = NULL; + } + Ptr& operator = ( T* p ){ + Ptr temp( p ); + swap( temp ); + return *this; + } + Ptr& operator = ( Ptr const& other ){ + Ptr temp( other ); + swap( temp ); + return *this; + } + void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } + T* get() { return m_p; } + const T* get() const{ return m_p; } + T& operator*() const { return *m_p; } + T* operator->() const { return m_p; } + bool operator !() const { return m_p == NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); } + +private: + T* m_p; +}; + +struct IShared : NonCopyable { + virtual ~IShared(); + virtual void addRef() const = 0; + virtual void release() const = 0; +}; + +template +struct SharedImpl : T { + + SharedImpl() : m_rc( 0 ){} + + virtual void addRef() const { + ++m_rc; + } + virtual void release() const { + if( --m_rc == 0 ) + delete this; + } + + mutable unsigned int m_rc; +}; + +} // end namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#include +#include +#include + +namespace Catch { + +class TestCase; +class Stream; +struct IResultCapture; +struct IRunner; +struct IGeneratorsForTest; +struct IConfig; + +struct IContext +{ + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; + virtual bool advanceGeneratorsForCurrentTest() = 0; + virtual Ptr getConfig() const = 0; +}; + +struct IMutableContext : IContext +{ + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( Ptr const& config ) = 0; +}; + +IContext& getCurrentContext(); +IMutableContext& getCurrentMutableContext(); +void cleanUpContext(); +Stream createStream( std::string const& streamName ); + +} + +// #included from: internal/catch_test_registry.hpp +#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED + +// #included from: catch_interfaces_testcase.h +#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED + +#include + +namespace Catch { + +class TestSpec; + +struct ITestCase : IShared { + virtual void invoke () const = 0; +protected: + virtual ~ITestCase(); +}; + +class TestCase; +struct IConfig; + +struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const = 0; + +}; +} + +namespace Catch { + +template +class MethodTestCase : public SharedImpl { + +public: + MethodTestCase( void (C::*method)() ) : m_method( method ) {} + + virtual void invoke() const { + C obj; + (obj.*m_method)(); + } + +private: + virtual ~MethodTestCase() {} + + void (C::*m_method)(); +}; + +typedef void(*TestFunction)(); + +struct NameAndDesc { + NameAndDesc( const char* _name = "", const char* _description= "" ) + : name( _name ), description( _description ) + {} + + const char* name; + const char* description; +}; + +struct AutoReg { + + AutoReg( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + + template + AutoReg( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + registerTestCase( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); + } + + void registerTestCase( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + + ~AutoReg(); + +private: + AutoReg( AutoReg const& ); + void operator= ( AutoReg const& ); +}; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( ... ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + +#else +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + +#endif + +// #included from: internal/catch_capture.hpp +#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + +// #included from: catch_result_builder.h +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED + +// #included from: catch_result_type.h +#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED + +namespace Catch { + +// ResultWas::OfType enum +struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + +inline bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; +} +inline bool isJustInfo( int flags ) { + return flags == ResultWas::Info; +} + +// ResultDisposition::Flags enum +struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + +inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast( static_cast( lhs ) | static_cast( rhs ) ); +} + +inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } +inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } +inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch + +// #included from: catch_assertionresult.h +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED + +#include + +namespace Catch { + +struct AssertionInfo +{ + AssertionInfo() {} + AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ); + + std::string macroName; + SourceLineInfo lineInfo; + std::string capturedExpression; + ResultDisposition::Flags resultDisposition; +}; + +struct AssertionResultData +{ + AssertionResultData() : resultType( ResultWas::Unknown ) {} + + std::string reconstructedExpression; + std::string message; + ResultWas::OfType resultType; +}; + +class AssertionResult { +public: + AssertionResult(); + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + ~AssertionResult(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionResult( AssertionResult const& ) = default; + AssertionResult( AssertionResult && ) = default; + AssertionResult& operator = ( AssertionResult const& ) = default; + AssertionResult& operator = ( AssertionResult && ) = default; +# endif + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + std::string getTestMacroName() const; + +protected: + AssertionInfo m_info; + AssertionResultData m_resultData; +}; + +} // end namespace Catch + +namespace Catch { + +struct TestFailureException{}; + +template class ExpressionLhs; + +struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + +struct CopyableStream { + CopyableStream() {} + CopyableStream( CopyableStream const& other ) { + oss << other.oss.str(); + } + CopyableStream& operator=( CopyableStream const& other ) { + oss.str(""); + oss << other.oss.str(); + return *this; + } + std::ostringstream oss; +}; + +class ResultBuilder { +public: + ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition ); + + template + ExpressionLhs operator <= ( T const& operand ); + ExpressionLhs operator <= ( bool value ); + + template + ResultBuilder& operator << ( T const& value ) { + m_stream.oss << value; + return *this; + } + + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + + ResultBuilder& setResultType( ResultWas::OfType result ); + ResultBuilder& setResultType( bool result ); + ResultBuilder& setLhs( std::string const& lhs ); + ResultBuilder& setRhs( std::string const& rhs ); + ResultBuilder& setOp( std::string const& op ); + + void endExpression(); + + std::string reconstructExpression() const; + AssertionResult build() const; + + void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); + void captureResult( ResultWas::OfType resultType ); + void captureExpression(); + void react(); + bool shouldDebugBreak() const; + bool allowThrows() const; + +private: + AssertionInfo m_assertionInfo; + AssertionResultData m_data; + struct ExprComponents { + ExprComponents() : testFalse( false ) {} + bool testFalse; + std::string lhs, rhs, op; + } m_exprComponents; + CopyableStream m_stream; + + bool m_shouldDebugBreak; + bool m_shouldThrow; +}; + +} // namespace Catch + +// Include after due to circular dependency: +// #included from: catch_expression_lhs.hpp +#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + +// #included from: catch_evaluate.hpp +#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#endif + +#include + +namespace Catch { +namespace Internal { + +enum Operator { + IsEqualTo, + IsNotEqualTo, + IsLessThan, + IsGreaterThan, + IsLessThanOrEqualTo, + IsGreaterThanOrEqualTo +}; + +template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; +template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; +template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; +template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; +template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; +template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; +template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; + +template +inline T& opCast(T const& t) { return const_cast(t); } + +// nullptr_t support based on pull request #154 from Konstantin Baumann +#ifdef CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } +#endif // CATCH_CONFIG_CPP11_NULLPTR + +// So the compare overloads can be operator agnostic we convey the operator as a template +// enum, which is used to specialise an Evaluator for doing the comparison. +template +class Evaluator{}; + +template +struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs) { + return opCast( lhs ) == opCast( rhs ); + } +}; +template +struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) != opCast( rhs ); + } +}; +template +struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) < opCast( rhs ); + } +}; +template +struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) > opCast( rhs ); + } +}; +template +struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) >= opCast( rhs ); + } +}; +template +struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) <= opCast( rhs ); + } +}; + +template +bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); +} + +// This level of indirection allows us to specialise for integer types +// to avoid signed/ unsigned warnings + +// "base" overload +template +bool compare( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); +} + +// unsigned X to int +template bool compare( unsigned int lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); +} +template bool compare( unsigned long lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); +} +template bool compare( unsigned char lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); +} + +// unsigned X to long +template bool compare( unsigned int lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); +} +template bool compare( unsigned long lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); +} +template bool compare( unsigned char lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); +} + +// int to unsigned X +template bool compare( int lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); +} +template bool compare( int lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); +} +template bool compare( int lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); +} + +// long to unsigned X +template bool compare( long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); +} +template bool compare( long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); +} +template bool compare( long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); +} + +// pointer to long (when comparing against NULL) +template bool compare( long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); +} +template bool compare( T* lhs, long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); +} + +// pointer to int (when comparing against NULL) +template bool compare( int lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); +} +template bool compare( T* lhs, int rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); +} + +#ifdef CATCH_CONFIG_CPP11_NULLPTR + // pointer to nullptr_t (when comparing against nullptr) + template bool compare( std::nullptr_t, T* rhs ) { + return Evaluator::evaluate( NULL, rhs ); + } + template bool compare( T* lhs, std::nullptr_t ) { + return Evaluator::evaluate( lhs, NULL ); + } +#endif // CATCH_CONFIG_CPP11_NULLPTR + +} // end of namespace Internal +} // end of namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// #included from: catch_tostring.h +#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED + +#include +#include +#include +#include +#include + +#ifdef __OBJC__ +// #included from: catch_objc_arc.hpp +#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED + +#import + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +#endif + +#ifdef CATCH_CONFIG_CPP11_TUPLE +#include +#endif + +#ifdef CATCH_CONFIG_CPP11_IS_ENUM +#include +#endif + +namespace Catch { + +// Why we're here. +template +std::string toString( T const& value ); + +// Built in overloads + +std::string toString( std::string const& value ); +std::string toString( std::wstring const& value ); +std::string toString( const char* const value ); +std::string toString( char* const value ); +std::string toString( const wchar_t* const value ); +std::string toString( wchar_t* const value ); +std::string toString( int value ); +std::string toString( unsigned long value ); +std::string toString( unsigned int value ); +std::string toString( const double value ); +std::string toString( const float value ); +std::string toString( bool value ); +std::string toString( char value ); +std::string toString( signed char value ); +std::string toString( unsigned char value ); + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ); +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); + std::string toString( NSObject* const& nsObject ); +#endif + +namespace Detail { + +extern std::string unprintableString; + +struct BorgType { + template BorgType( T const& ); +}; + +struct TrueType { char sizer[1]; }; +struct FalseType { char sizer[2]; }; + +TrueType& testStreamable( std::ostream& ); +FalseType testStreamable( FalseType ); + +FalseType operator<<( std::ostream const&, BorgType const& ); + +template +struct IsStreamInsertable { + static std::ostream &s; + static T const&t; + enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; +}; + +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template::value + > + struct EnumStringMaker + { + static std::string convert( T const& ) { return unprintableString; } + }; + + template + struct EnumStringMaker + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast::type>(v) + ); + } + }; +#endif +template +struct StringMakerBase { +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template + static std::string convert( T const& v ) + { + return EnumStringMaker::convert( v ); + } +#else + template + static std::string convert( T const& ) { return unprintableString; } +#endif +}; + +template<> +struct StringMakerBase { + template + static std::string convert( T const& _value ) { + std::ostringstream oss; + oss << _value; + return oss.str(); + } +}; + +std::string rawMemoryToString( const void *object, std::size_t size ); + +template +inline std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); +} + +} // end namespace Detail + +template +struct StringMaker : + Detail::StringMakerBase::value> {}; + +template +struct StringMaker { + template + static std::string convert( U* p ) { + if( !p ) + return INTERNAL_CATCH_STRINGIFY( NULL ); + else + return Detail::rawMemoryToString( p ); + } +}; + +template +struct StringMaker { + static std::string convert( R C::* p ) { + if( !p ) + return INTERNAL_CATCH_STRINGIFY( NULL ); + else + return Detail::rawMemoryToString( p ); + } +}; + +namespace Detail { +template +std::string rangeToString( InputIterator first, InputIterator last ); +} + +//template +//struct StringMaker > { +// static std::string convert( std::vector const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + +template +std::string toString( std::vector const& v ) { + return Detail::rangeToString( v.begin(), v.end() ); +} + +#ifdef CATCH_CONFIG_CPP11_TUPLE + +// toString for tuples +namespace TupleDetail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get(tuple)); + ElementPrinter::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template +struct StringMaker> { + + static std::string convert( const std::tuple& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter>::print( tuple, os ); + os << " }"; + return os.str(); + } +}; +#endif // CATCH_CONFIG_CPP11_TUPLE + +namespace Detail { +template +std::string makeString( T const& value ) { + return StringMaker::convert( value ); +} +} // end namespace Detail + +/// \brief converts any type to a string +/// +/// The default template forwards on to ostringstream - except when an +/// ostringstream overload does not exist - in which case it attempts to detect +/// that and writes {?}. +/// Overload (not specialise) this template for custom typs that you don't want +/// to provide an ostream overload for. +template +std::string toString( T const& value ) { + return StringMaker::convert( value ); +} + +namespace Detail { +template +std::string rangeToString( InputIterator first, InputIterator last ) { + std::ostringstream oss; + oss << "{ "; + if( first != last ) { + oss << Catch::toString( *first ); + for( ++first ; first != last ; ++first ) + oss << ", " << Catch::toString( *first ); + } + oss << " }"; + return oss.str(); +} +} + +} // end namespace Catch + +namespace Catch { + +// Wraps the LHS of an expression and captures the operator and RHS (if any) - +// wrapping them all in a ResultBuilder object +template +class ExpressionLhs { + ExpressionLhs& operator = ( ExpressionLhs const& ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs& operator = ( ExpressionLhs && ) = delete; +# endif + +public: + ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs( ExpressionLhs const& ) = default; + ExpressionLhs( ExpressionLhs && ) = default; +# endif + + template + ResultBuilder& operator == ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator != ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator < ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator > ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator <= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator >= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator == ( bool rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator != ( bool rhs ) { + return captureExpression( rhs ); + } + + void endExpression() { + bool value = m_lhs ? true : false; + m_rb + .setLhs( Catch::toString( value ) ) + .setResultType( value ) + .endExpression(); + } + + // Only simple binary expressions are allowed on the LHS. + // If more complex compositions are required then place the sub expression in parentheses + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + +private: + template + ResultBuilder& captureExpression( RhsT const& rhs ) { + return m_rb + .setResultType( Internal::compare( m_lhs, rhs ) ) + .setLhs( Catch::toString( m_lhs ) ) + .setRhs( Catch::toString( rhs ) ) + .setOp( Internal::OperatorTraits::getName() ); + } + +private: + ResultBuilder& m_rb; + T m_lhs; +}; + +} // end namespace Catch + + +namespace Catch { + +template +inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { + return ExpressionLhs( *this, operand ); +} + +inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { + return ExpressionLhs( *this, value ); +} + +} // namespace Catch + +// #included from: catch_message.h +#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED + +#include + +namespace Catch { + +struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + SourceLineInfo lineInfo; + ResultWas::OfType type; + std::string message; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const { + return sequence == other.sequence; + } + bool operator < ( MessageInfo const& other ) const { + return sequence < other.sequence; + } +private: + static unsigned int globalCount; +}; + +struct MessageBuilder { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + : m_info( macroName, lineInfo, type ) + {} + + template + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + std::ostringstream m_stream; +}; + +class ScopedMessage { +public: + ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage const& other ); + ~ScopedMessage(); + + MessageInfo m_info; +}; + +} // end namespace Catch + +// #included from: catch_interfaces_capture.h +#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED + +#include + +namespace Catch { + +class TestCase; +class AssertionResult; +struct AssertionInfo; +struct SectionInfo; +struct MessageInfo; +class ScopedMessageBuilder; +struct Counts; + +struct IResultCapture { + + virtual ~IResultCapture(); + + virtual void assertionEnded( AssertionResult const& result ) = 0; + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + + virtual void handleFatalErrorCondition( std::string const& message ) = 0; +}; + +IResultCapture& getResultCapture(); +} + +// #included from: catch_debugger.h +#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED + +// #included from: catch_platform.h +#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED + +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_IPHONE +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CATCH_PLATFORM_WINDOWS +#endif + +#include + +namespace Catch{ + +bool isDebuggerActive(); +void writeToDebugConsole( std::string const& text ); +} + +#ifdef CATCH_PLATFORM_MAC + + // The following code snippet based on: + // http://cocoawithlove.com/2008/03/break-into-debugger.html + #ifdef DEBUG + #if defined(__ppc64__) || defined(__ppc__) + #define CATCH_BREAK_INTO_DEBUGGER() \ + if( Catch::isDebuggerActive() ) { \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ); \ + } + #else + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} + #endif + #endif + +#elif defined(_MSC_VER) + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } +#endif + +#ifndef CATCH_BREAK_INTO_DEBUGGER +#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); +#endif + +// #included from: catch_interfaces_runner.h +#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED + +namespace Catch { +class TestCase; + +struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; +}; +} + +/////////////////////////////////////////////////////////////////////////////// +// In the event of a failure works out if the debugger needs to be invoked +// and/or an exception thrown and takes appropriate action. +// This needs to be done as a macro so the debugger will stop in the user +// source code rather than in Catch library code +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + resultBuilder.react(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + ( __catchResult <= expr ).endExpression(); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( !Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( ... ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( exceptionType ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#else +#define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << log + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( log, macroName ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \ + try { \ + std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ + __catchResult \ + .setLhs( Catch::toString( arg ) ) \ + .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ + .setOp( "matches" ) \ + .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ + __catchResult.captureExpression(); \ + } catch( ... ) { \ + __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +// #included from: internal/catch_section.h +#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED + +// #included from: catch_section_info.h +#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED + +namespace Catch { + +struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; +}; + +} // end namespace Catch + +// #included from: catch_totals.hpp +#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED + +#include + +namespace Catch { + +struct Counts { + Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} + + Counts operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + Counts& operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t total() const { + return passed + failed + failedButOk; + } + bool allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool allOk() const { + return failed == 0; + } + + std::size_t passed; + std::size_t failed; + std::size_t failedButOk; +}; + +struct Totals { + + Totals operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + + Totals& operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Counts assertions; + Counts testCases; +}; +} + +// #included from: catch_timer.h +#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED + +#ifdef CATCH_PLATFORM_WINDOWS +typedef unsigned long long uint64_t; +#else +#include +#endif + +namespace Catch { + +class Timer { +public: + Timer() : m_ticks( 0 ) {} + void start(); + unsigned int getElapsedMicroseconds() const; + unsigned int getElapsedMilliseconds() const; + double getElapsedSeconds() const; + +private: + uint64_t m_ticks; +}; + +} // namespace Catch + +#include + +namespace Catch { + +class Section : NonCopyable { +public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + operator bool() const; + +private: + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; +}; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_SECTION( ... ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#else +#define INTERNAL_CATCH_SECTION( name, desc ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) +#endif + +// #included from: internal/catch_generators.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + +template +struct IGenerator { + virtual ~IGenerator() {} + virtual T getValue( std::size_t index ) const = 0; + virtual std::size_t size () const = 0; +}; + +template +class BetweenGenerator : public IGenerator { +public: + BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} + + virtual T getValue( std::size_t index ) const { + return m_from+static_cast( index ); + } + + virtual std::size_t size() const { + return static_cast( 1+m_to-m_from ); + } + +private: + + T m_from; + T m_to; +}; + +template +class ValuesGenerator : public IGenerator { +public: + ValuesGenerator(){} + + void add( T value ) { + m_values.push_back( value ); + } + + virtual T getValue( std::size_t index ) const { + return m_values[index]; + } + + virtual std::size_t size() const { + return m_values.size(); + } + +private: + std::vector m_values; +}; + +template +class CompositeGenerator { +public: + CompositeGenerator() : m_totalSize( 0 ) {} + + // *** Move semantics, similar to auto_ptr *** + CompositeGenerator( CompositeGenerator& other ) + : m_fileInfo( other.m_fileInfo ), + m_totalSize( 0 ) + { + move( other ); + } + + CompositeGenerator& setFileInfo( const char* fileInfo ) { + m_fileInfo = fileInfo; + return *this; + } + + ~CompositeGenerator() { + deleteAll( m_composed ); + } + + operator T () const { + size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); + + typename std::vector*>::const_iterator it = m_composed.begin(); + typename std::vector*>::const_iterator itEnd = m_composed.end(); + for( size_t index = 0; it != itEnd; ++it ) + { + const IGenerator* generator = *it; + if( overallIndex >= index && overallIndex < index + generator->size() ) + { + return generator->getValue( overallIndex-index ); + } + index += generator->size(); + } + CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); + return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so + } + + void add( const IGenerator* generator ) { + m_totalSize += generator->size(); + m_composed.push_back( generator ); + } + + CompositeGenerator& then( CompositeGenerator& other ) { + move( other ); + return *this; + } + + CompositeGenerator& then( T value ) { + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( value ); + add( valuesGen ); + return *this; + } + +private: + + void move( CompositeGenerator& other ) { + std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); + m_totalSize += other.m_totalSize; + other.m_composed.clear(); + } + + std::vector*> m_composed; + std::string m_fileInfo; + size_t m_totalSize; +}; + +namespace Generators +{ +template +CompositeGenerator between( T from, T to ) { + CompositeGenerator generators; + generators.add( new BetweenGenerator( from, to ) ); + return generators; +} + +template +CompositeGenerator values( T val1, T val2 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + generators.add( valuesGen ); + return generators; +} + +template +CompositeGenerator values( T val1, T val2, T val3 ){ + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + generators.add( valuesGen ); + return generators; +} + +template +CompositeGenerator values( T val1, T val2, T val3, T val4 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + valuesGen->add( val4 ); + generators.add( valuesGen ); + return generators; +} + +} // end namespace Generators + +using namespace Generators; + +} // end namespace Catch + +#define INTERNAL_CATCH_LINESTR2( line ) #line +#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) + +#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) + +// #included from: internal/catch_interfaces_exception.h +#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED + +#include +// #included from: catch_interfaces_registry_hub.h +#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED + +#include + +namespace Catch { + +class TestCase; +struct ITestCaseRegistry; +struct IExceptionTranslatorRegistry; +struct IExceptionTranslator; +struct IReporterRegistry; +struct IReporterFactory; + +struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; +}; + +struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; +}; + +IRegistryHub& getRegistryHub(); +IMutableRegistryHub& getMutableRegistryHub(); +void cleanUp(); +std::string translateActiveException(); + +} + + +namespace Catch { + +typedef std::string(*exceptionTranslateFunction)(); + +struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate() const = 0; +}; + +struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; +}; + +class ExceptionTranslatorRegistrar { + template + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + virtual std::string translate() const { + try { + throw; + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + +public: + template + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator( translateFunction ) ); + } +}; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) + +// #included from: internal/catch_approx.hpp +#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED + +#include +#include + +namespace Catch { +namespace Detail { + +class Approx { +public: + explicit Approx ( double value ) + : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_scale( 1.0 ), + m_value( value ) + {} + + Approx( Approx const& other ) + : m_epsilon( other.m_epsilon ), + m_scale( other.m_scale ), + m_value( other.m_value ) + {} + + static Approx custom() { + return Approx( 0 ); + } + + Approx operator()( double value ) { + Approx approx( value ); + approx.epsilon( m_epsilon ); + approx.scale( m_scale ); + return approx; + } + + friend bool operator == ( double lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); + } + + friend bool operator == ( Approx const& lhs, double rhs ) { + return operator==( rhs, lhs ); + } + + friend bool operator != ( double lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + friend bool operator != ( Approx const& lhs, double rhs ) { + return !operator==( rhs, lhs ); + } + + Approx& epsilon( double newEpsilon ) { + m_epsilon = newEpsilon; + return *this; + } + + Approx& scale( double newScale ) { + m_scale = newScale; + return *this; + } + + std::string toString() const { + std::ostringstream oss; + oss << "Approx( " << Catch::toString( m_value ) << " )"; + return oss.str(); + } + +private: + double m_epsilon; + double m_scale; + double m_value; +}; +} + +template<> +inline std::string toString( Detail::Approx const& value ) { + return value.toString(); +} + +} // end namespace Catch + +// #included from: internal/catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { +namespace Impl { + +template +struct Matcher : SharedImpl +{ + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; +}; + +template +struct MatcherImpl : Matcher { + + virtual Ptr > clone() const { + return Ptr >( new DerivedT( static_cast( *this ) ) ); + } +}; + +namespace Generic { + +template +class AllOf : public MatcherImpl, ExpressionT> { +public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + +private: + std::vector > > m_matchers; +}; + +template +class AnyOf : public MatcherImpl, ExpressionT> { +public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + +private: + std::vector > > m_matchers; +}; + +} + +namespace StdString { + +inline std::string makeString( std::string const& str ) { return str; } +inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + +struct Equals : MatcherImpl { + Equals( std::string const& str ) : m_str( str ){} + Equals( Equals const& other ) : m_str( other.m_str ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_str == expr; + } + virtual std::string toString() const { + return "equals: \"" + m_str + "\""; + } + + std::string m_str; +}; + +struct Contains : MatcherImpl { + Contains( std::string const& substr ) : m_substr( substr ){} + Contains( Contains const& other ) : m_substr( other.m_substr ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return expr.find( m_substr ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_substr + "\""; + } + + std::string m_substr; +}; + +struct StartsWith : MatcherImpl { + StartsWith( std::string const& substr ) : m_substr( substr ){} + StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return expr.find( m_substr ) == 0; + } + virtual std::string toString() const { + return "starts with: \"" + m_substr + "\""; + } + + std::string m_substr; +}; + +struct EndsWith : MatcherImpl { + EndsWith( std::string const& substr ) : m_substr( substr ){} + EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return expr.find( m_substr ) == expr.size() - m_substr.size(); + } + virtual std::string toString() const { + return "ends with: \"" + m_substr + "\""; + } + + std::string m_substr; +}; +} // namespace StdString +} // namespace Impl + +// The following functions create the actual matcher objects. +// This allows the types to be inferred +template +inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ); +} +template +inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); +} +template +inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ); +} +template +inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); +} + +inline Impl::StdString::Equals Equals( std::string const& str ) { +return Impl::StdString::Equals( str ); +} +inline Impl::StdString::Equals Equals( const char* str ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ) ); +} +inline Impl::StdString::Contains Contains( std::string const& substr ) { +return Impl::StdString::Contains( substr ); +} +inline Impl::StdString::Contains Contains( const char* substr ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ) ); +} +inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { +return Impl::StdString::StartsWith( substr ); +} +inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); +} +inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { +return Impl::StdString::EndsWith( substr ); +} +inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); +} + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + +// #included from: internal/catch_interfaces_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED + +// #included from: catch_tag_alias.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED + +#include + +namespace Catch { + +struct TagAlias { + TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} + + std::string tag; + SourceLineInfo lineInfo; +}; + +struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); +}; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +// #included from: catch_option.hpp +#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED + +namespace Catch { + +// An optional type +template +class Option { +public: + Option() : nullableValue( NULL ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : NULL ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = NULL; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != NULL; } + bool none() const { return nullableValue == NULL; } + + bool operator !() const { return nullableValue == NULL; } + operator SafeBool::type() const { + return SafeBool::makeSafe( some() ); + } + +private: + T* nullableValue; + char storage[sizeof(T)]; +}; + +} // end namespace Catch + +namespace Catch { + +struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + virtual Option find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); +}; + +} // end namespace Catch + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// #included from: internal/catch_test_case_info.h +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED + +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + +struct ITestCase; + +struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ); + + TestCaseInfo( TestCaseInfo const& other ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string name; + std::string className; + std::string description; + std::set tags; + std::set lcaseTags; + std::string tagsAsString; + SourceLineInfo lineInfo; + SpecialProperties properties; +}; + +class TestCase : public TestCaseInfo { +public: + + TestCase( ITestCase* testCase, TestCaseInfo const& info ); + TestCase( TestCase const& other ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + void swap( TestCase& other ); + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + TestCase& operator = ( TestCase const& other ); + +private: + Ptr test; +}; + +TestCase makeTestCase( ITestCase* testCase, + std::string const& className, + std::string const& name, + std::string const& description, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + +#ifdef __OBJC__ +// #included from: internal/catch_objc.hpp +#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED + +#import + +#include + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public SharedImpl { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline size_t registerTestMethods() { + size_t noTestMethods = 0; + int noClasses = objc_getClassList( NULL, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + template + struct StringHolder : MatcherImpl{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + NSString* m_substr; + }; + + struct Equals : StringHolder { + Equals( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + virtual std::string toString() const { + return "equals string: " + Catch::toString( m_substr ); + } + }; + + struct Contains : StringHolder { + Contains( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + virtual std::string toString() const { + return "contains string: " + Catch::toString( m_substr ); + } + }; + + struct StartsWith : StringHolder { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + virtual std::string toString() const { + return "starts with: " + Catch::toString( m_substr ); + } + }; + struct EndsWith : StringHolder { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + virtual std::string toString() const { + return "ends with: " + Catch::toString( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_TEST_CASE( name, desc )\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ +{\ +return @ name; \ +}\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ +{ \ +return @ desc; \ +} \ +-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) + +#endif + +#ifdef CATCH_IMPL +// #included from: internal/catch_impl.hpp +#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED + +// Collect all the implementation files together here +// These are the equivalent of what would usually be cpp files + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// #included from: ../catch_runner.hpp +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +// #included from: internal/catch_commandline.hpp +#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + +// #included from: catch_config.hpp +#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED + +// #included from: catch_test_spec_parser.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_test_spec.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +#include +#include + +namespace Catch { + + class TestSpec { + struct Pattern : SharedImpl<> { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + class NamePattern : public Pattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) { + if( startsWith( m_name, "*" ) ) { + m_name = m_name.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_name, "*" ) ) { + m_name = m_name.substr( 0, m_name.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_name == toLower( testCase.name ); + case WildcardAtStart: + return endsWith( toLower( testCase.name ), m_name ); + case WildcardAtEnd: + return startsWith( toLower( testCase.name ), m_name ); + case WildcardAtBothEnds: + return contains( toLower( testCase.name ), m_name ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string m_name; + WildcardPosition m_wildcard; + }; + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); + } + private: + std::string m_tag; + }; + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + private: + Ptr m_underlyingPattern; + }; + + struct Filter { + std::vector > m_patterns; + + bool matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + if( !(*it)->matches( testCase ) ) + return false; + return true; + } + }; + + public: + bool hasFilters() const { + return !m_filters.empty(); + } + bool matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) + if( it->matches( testCase ) ) + return true; + return false; + } + + private: + std::vector m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag }; + Mode m_mode; + bool m_exclusion; + std::size_t m_start, m_pos; + std::string m_arg; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern(); + return *this; + } + TestSpec testSpec() { + addFilter(); + return m_testSpec; + } + private: + void visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern(); + startNewMode( Tag, ++m_pos ); + } + } + else if( m_mode == QuotedName && c == '"' ) + addPattern(); + else if( m_mode == Tag && c == ']' ) + addPattern(); + } + void startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + template + void addPattern() { + std::string token = subString(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + Ptr pattern = new T( token ); + if( m_exclusion ) + pattern = new TestSpec::ExcludedPattern( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + void addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + }; + inline TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// #included from: catch_interfaces_config.h +#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct Verbosity { enum Level { + NoOutput = 0, + Quiet, + Normal + }; }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + + class TestSpec; + + struct IConfig : IShared { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual bool forceColour() const = 0; + }; +} + +// #included from: catch_stream.h +#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED + +#include + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + class Stream { + public: + Stream(); + Stream( std::streambuf* _streamBuf, bool _isOwned ); + void release(); + + std::streambuf* streamBuf; + + private: + bool isOwned; + }; + + std::ostream& cout(); + std::ostream& cerr(); +} + +#include +#include +#include +#include +#include + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct ConfigData { + + ConfigData() + : listTests( false ), + listTags( false ), + listReporters( false ), + listTestNamesOnly( false ), + showSuccessfulTests( false ), + shouldDebugBreak( false ), + noThrow( false ), + showHelp( false ), + showInvisibles( false ), + forceColour( false ), + abortAfter( -1 ), + rngSeed( 0 ), + verbosity( Verbosity::Normal ), + warnings( WarnAbout::Nothing ), + showDurations( ShowDurations::DefaultForReporter ), + runOrder( RunTests::InDeclarationOrder ) + {} + + bool listTests; + bool listTags; + bool listReporters; + bool listTestNamesOnly; + + bool showSuccessfulTests; + bool shouldDebugBreak; + bool noThrow; + bool showHelp; + bool showInvisibles; + bool forceColour; + + int abortAfter; + unsigned int rngSeed; + + Verbosity::Level verbosity; + WarnAbout::What warnings; + ShowDurations::OrNot showDurations; + RunTests::InWhatOrder runOrder; + + std::string reporterName; + std::string outputFilename; + std::string name; + std::string processName; + + std::vector testsOrTags; + }; + + class Config : public SharedImpl { + private: + Config( Config const& other ); + Config& operator = ( Config const& other ); + virtual void dummy(); + public: + + Config() + : m_os( Catch::cout().rdbuf() ) + {} + + Config( ConfigData const& data ) + : m_data( data ), + m_os( Catch::cout().rdbuf() ) + { + if( !data.testsOrTags.empty() ) { + TestSpecParser parser( ITagAliasRegistry::get() ); + for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) + parser.parse( data.testsOrTags[i] ); + m_testSpec = parser.testSpec(); + } + } + + virtual ~Config() { + m_os.rdbuf( Catch::cout().rdbuf() ); + m_stream.release(); + } + + void setFilename( std::string const& filename ) { + m_data.outputFilename = filename; + } + + std::string const& getFilename() const { + return m_data.outputFilename ; + } + + bool listTests() const { return m_data.listTests; } + bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool listTags() const { return m_data.listTags; } + bool listReporters() const { return m_data.listReporters; } + + std::string getProcessName() const { return m_data.processName; } + + bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } + + void setStreamBuf( std::streambuf* buf ) { + m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() ); + } + + void useStream( std::string const& streamName ) { + Stream stream = createStream( streamName ); + setStreamBuf( stream.streamBuf ); + m_stream.release(); + m_stream = stream; + } + + std::string getReporterName() const { return m_data.reporterName; } + + int abortAfter() const { return m_data.abortAfter; } + + TestSpec const& testSpec() const { return m_testSpec; } + + bool showHelp() const { return m_data.showHelp; } + bool showInvisibles() const { return m_data.showInvisibles; } + + // IConfig interface + virtual bool allowThrows() const { return !m_data.noThrow; } + virtual std::ostream& stream() const { return m_os; } + virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } + virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } + virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } + virtual unsigned int rngSeed() const { return m_data.rngSeed; } + virtual bool forceColour() const { return m_data.forceColour; } + + private: + ConfigData m_data; + + Stream m_stream; + mutable std::ostream m_os; + TestSpec m_testSpec; + }; + +} // end namespace Catch + +// #included from: catch_clara.h +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +// Declare Clara inside the Catch namespace +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { +// #included from: ../external/clara.h + +// Only use header guard if we are not using an outer namespace +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE +#define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } +#endif + +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE + +// ----------- #included from tbc_text_format.h ----------- + +// Only use header guard if we are not using an outer namespace +#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) +#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#define TBC_TEXT_FORMAT_H_INCLUDED +#endif + +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TBC_TEXT_FORMAT_H_INCLUDED + +// ----------- end of #include from tbc_text_format.h ----------- +// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h + +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE + +#include +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE +#endif + +namespace Clara { + + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + + namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; + } + + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + + template struct IsBool { static const bool value = false; }; + template<> struct IsBool { static const bool value = true; }; + + template + void convertInto( std::string const& _source, T& _dest ) { + std::stringstream ss; + ss << _source; + ss >> _dest; + if( ss.fail() ) + throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); + } + inline void convertInto( std::string const& _source, std::string& _dest ) { + _dest = _source; + } + inline void convertInto( std::string const& _source, bool& _dest ) { + std::string sourceLC = _source; + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); + if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) + _dest = true; + else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) + _dest = false; + else + throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); + } + inline void convertInto( bool _source, bool& _dest ) { + _dest = _source; + } + template + inline void convertInto( bool, T& ) { + throw std::runtime_error( "Invalid conversion" ); + } + + template + struct IArgFunction { + virtual ~IArgFunction() {} +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + IArgFunction() = default; + IArgFunction( IArgFunction const& ) = default; +# endif + virtual void set( ConfigT& config, std::string const& value ) const = 0; + virtual void setFlag( ConfigT& config ) const = 0; + virtual bool takesArg() const = 0; + virtual IArgFunction* clone() const = 0; + }; + + template + class BoundArgFunction { + public: + BoundArgFunction() : functionObj( NULL ) {} + BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {} + BoundArgFunction& operator = ( BoundArgFunction const& other ) { + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL; + delete functionObj; + functionObj = newFunctionObj; + return *this; + } + ~BoundArgFunction() { delete functionObj; } + + void set( ConfigT& config, std::string const& value ) const { + functionObj->set( config, value ); + } + void setFlag( ConfigT& config ) const { + functionObj->setFlag( config ); + } + bool takesArg() const { return functionObj->takesArg(); } + + bool isSet() const { + return functionObj != NULL; + } + private: + IArgFunction* functionObj; + }; + + template + struct NullBinder : IArgFunction{ + virtual void set( C&, std::string const& ) const {} + virtual void setFlag( C& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction* clone() const { return new NullBinder( *this ); } + }; + + template + struct BoundDataMember : IArgFunction{ + BoundDataMember( M C::* _member ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + convertInto( stringValue, p.*member ); + } + virtual void setFlag( C& p ) const { + convertInto( true, p.*member ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } + M C::* member; + }; + template + struct BoundUnaryMethod : IArgFunction{ + BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + (p.*member)( value ); + } + virtual void setFlag( C& p ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + (p.*member)( value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } + void (C::*member)( M ); + }; + template + struct BoundNullaryMethod : IArgFunction{ + BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + (p.*member)(); + } + virtual void setFlag( C& p ) const { + (p.*member)(); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } + void (C::*member)(); + }; + + template + struct BoundUnaryFunction : IArgFunction{ + BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + function( obj ); + } + virtual void setFlag( C& p ) const { + function( p ); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } + void (*function)( C& ); + }; + + template + struct BoundBinaryFunction : IArgFunction{ + BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + function( obj, value ); + } + virtual void setFlag( C& obj ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + function( obj, value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } + void (*function)( C&, T ); + }; + + } // namespace Detail + + struct Parser { + Parser() : separators( " \t=:" ) {} + + struct Token { + enum Type { Positional, ShortOpt, LongOpt }; + Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} + Type type; + std::string data; + }; + + void parseIntoTokens( int argc, char const * const * argv, std::vector& tokens ) const { + const std::string doubleDash = "--"; + for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) + parseIntoTokens( argv[i] , tokens); + } + void parseIntoTokens( std::string arg, std::vector& tokens ) const { + while( !arg.empty() ) { + Parser::Token token( Parser::Token::Positional, arg ); + arg = ""; + if( token.data[0] == '-' ) { + if( token.data.size() > 1 && token.data[1] == '-' ) { + token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); + } + else { + token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); + if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { + arg = "-" + token.data.substr( 1 ); + token.data = token.data.substr( 0, 1 ); + } + } + } + if( token.type != Parser::Token::Positional ) { + std::size_t pos = token.data.find_first_of( separators ); + if( pos != std::string::npos ) { + arg = token.data.substr( pos+1 ); + token.data = token.data.substr( 0, pos ); + } + } + tokens.push_back( token ); + } + } + std::string separators; + }; + + template + struct CommonArgProperties { + CommonArgProperties() {} + CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} + + Detail::BoundArgFunction boundField; + std::string description; + std::string detail; + std::string placeholder; // Only value if boundField takes an arg + + bool takesArg() const { + return !placeholder.empty(); + } + void validate() const { + if( !boundField.isSet() ) + throw std::logic_error( "option not bound" ); + } + }; + struct OptionArgProperties { + std::vector shortNames; + std::string longName; + + bool hasShortName( std::string const& shortName ) const { + return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); + } + bool hasLongName( std::string const& _longName ) const { + return _longName == longName; + } + }; + struct PositionalArgProperties { + PositionalArgProperties() : position( -1 ) {} + int position; // -1 means non-positional (floating) + + bool isFixedPositional() const { + return position != -1; + } + }; + + template + class CommandLine { + + struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { + Arg() {} + Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} + + using CommonArgProperties::placeholder; // !TBD + + std::string dbgName() const { + if( !longName.empty() ) + return "--" + longName; + if( !shortNames.empty() ) + return "-" + shortNames[0]; + return "positional args"; + } + std::string commands() const { + std::ostringstream oss; + bool first = true; + std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); + for(; it != itEnd; ++it ) { + if( first ) + first = false; + else + oss << ", "; + oss << "-" << *it; + } + if( !longName.empty() ) { + if( !first ) + oss << ", "; + oss << "--" << longName; + } + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; + return oss.str(); + } + }; + + // NOTE: std::auto_ptr is deprecated in c++11/c++0x +#if defined(__cplusplus) && __cplusplus > 199711L + typedef std::unique_ptr ArgAutoPtr; +#else + typedef std::auto_ptr ArgAutoPtr; +#endif + + friend void addOptName( Arg& arg, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( Arg& arg, int position ) + { + arg.position = position; + } + + class ArgBuilder { + public: + ArgBuilder( Arg* arg ) : m_arg( arg ) {} + + // Bind a non-boolean data member (requires placeholder string) + template + void bind( M C::* field, std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + m_arg->placeholder = placeholder; + } + // Bind a boolean data member (no placeholder required) + template + void bind( bool C::* field ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + } + + // Bind a method taking a single, non-boolean argument (requires a placeholder string) + template + void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + m_arg->placeholder = placeholder; + } + + // Bind a method taking a single, boolean argument (no placeholder string required) + template + void bind( void (C::* unaryMethod)( bool ) ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + } + + // Bind a method that takes no arguments (will be called if opt is present) + template + void bind( void (C::* nullaryMethod)() ) { + m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); + } + + // Bind a free function taking a single argument - the object to operate on (no placeholder string required) + template + void bind( void (* unaryFunction)( C& ) ) { + m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); + } + + // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) + template + void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); + m_arg->placeholder = placeholder; + } + + ArgBuilder& describe( std::string const& description ) { + m_arg->description = description; + return *this; + } + ArgBuilder& detail( std::string const& detail ) { + m_arg->detail = detail; + return *this; + } + + protected: + Arg* m_arg; + }; + + class OptBuilder : public ArgBuilder { + public: + OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *ArgBuilder::m_arg, optName ); + return *this; + } + }; + + public: + + CommandLine() + : m_boundProcessName( new Detail::NullBinder() ), + m_highestSpecifiedArgPosition( 0 ), + m_throwOnUnrecognisedTokens( false ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), + m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) + { + if( other.m_floatingArg.get() ) + m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); + } + + CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { + m_throwOnUnrecognisedTokens = shouldThrow; + return *this; + } + + OptBuilder operator[]( std::string const& optName ) { + m_options.push_back( Arg() ); + addOptName( m_options.back(), optName ); + OptBuilder builder( &m_options.back() ); + return builder; + } + + ArgBuilder operator[]( int position ) { + m_positionalArgs.insert( std::make_pair( position, Arg() ) ); + if( position > m_highestSpecifiedArgPosition ) + m_highestSpecifiedArgPosition = position; + setPositionalArg( m_positionalArgs[position], position ); + ArgBuilder builder( &m_positionalArgs[position] ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + if( m_floatingArg.get() ) + throw std::logic_error( "Only one unpositional argument can be added" ); + m_floatingArg.reset( new Arg() ); + ArgBuilder builder( m_floatingArg.get() ); + return builder; + } + + template + void bindProcessName( M C::* field ) { + m_boundProcessName = new Detail::BoundDataMember( field ); + } + template + void bindProcessName( void (C::*_unaryMethod)( M ) ) { + m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); + } + + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { + typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; + std::size_t maxWidth = 0; + for( it = itBegin; it != itEnd; ++it ) + maxWidth = (std::max)( maxWidth, it->commands().size() ); + + for( it = itBegin; it != itEnd; ++it ) { + Detail::Text usage( it->commands(), Detail::TextAttributes() + .setWidth( maxWidth+indent ) + .setIndent( indent ) ); + Detail::Text desc( it->description, Detail::TextAttributes() + .setWidth( width - maxWidth - 3 ) ); + + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; + os << usageCol; + + if( i < desc.size() && !desc[i].empty() ) + os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) + << desc[i]; + os << "\n"; + } + } + } + std::string optUsage() const { + std::ostringstream oss; + optUsage( oss ); + return oss.str(); + } + + void argSynopsis( std::ostream& os ) const { + for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { + if( i > 1 ) + os << " "; + typename std::map::const_iterator it = m_positionalArgs.find( i ); + if( it != m_positionalArgs.end() ) + os << "<" << it->second.placeholder << ">"; + else if( m_floatingArg.get() ) + os << "<" << m_floatingArg->placeholder << ">"; + else + throw std::logic_error( "non consecutive positional arguments with no floating args" ); + } + // !TBD No indication of mandatory args + if( m_floatingArg.get() ) { + if( m_highestSpecifiedArgPosition > 1 ) + os << " "; + os << "[<" << m_floatingArg->placeholder << "> ...]"; + } + } + std::string argSynopsis() const { + std::ostringstream oss; + argSynopsis( oss ); + return oss.str(); + } + + void usage( std::ostream& os, std::string const& procName ) const { + validate(); + os << "usage:\n " << procName << " "; + argSynopsis( os ); + if( !m_options.empty() ) { + os << " [options]\n\nwhere options are: \n"; + optUsage( os, 2 ); + } + os << "\n"; + } + std::string usage( std::string const& procName ) const { + std::ostringstream oss; + usage( oss, procName ); + return oss.str(); + } + + ConfigT parse( int argc, char const * const * argv ) const { + ConfigT config; + parseInto( argc, argv, config ); + return config; + } + + std::vector parseInto( int argc, char const * const * argv, ConfigT& config ) const { + std::string processName = argv[0]; + std::size_t lastSlash = processName.find_last_of( "/\\" ); + if( lastSlash != std::string::npos ) + processName = processName.substr( lastSlash+1 ); + m_boundProcessName.set( config, processName ); + std::vector tokens; + Parser parser; + parser.parseIntoTokens( argc, argv, tokens ); + return populate( tokens, config ); + } + + std::vector populate( std::vector const& tokens, ConfigT& config ) const { + validate(); + std::vector unusedTokens = populateOptions( tokens, config ); + unusedTokens = populateFixedArgs( unusedTokens, config ); + unusedTokens = populateFloatingArgs( unusedTokens, config ); + return unusedTokens; + } + + std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + std::vector errors; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); + for(; it != itEnd; ++it ) { + Arg const& arg = *it; + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + errors.push_back( "Expected argument to option: " + token.data ); + else + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.setFlag( config ); + } + break; + } + } + catch( std::exception& ex ) { + errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); + } + } + if( it == itEnd ) { + if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) + unusedTokens.push_back( token ); + else if( errors.empty() && m_throwOnUnrecognisedTokens ) + errors.push_back( "unrecognised option: " + token.data ); + } + } + if( !errors.empty() ) { + std::ostringstream oss; + for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); + it != itEnd; + ++it ) { + if( it != errors.begin() ) + oss << "\n"; + oss << *it; + } + throw std::runtime_error( oss.str() ); + } + return unusedTokens; + } + std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + int position = 1; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::map::const_iterator it = m_positionalArgs.find( position ); + if( it != m_positionalArgs.end() ) + it->second.boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + if( token.type == Parser::Token::Positional ) + position++; + } + return unusedTokens; + } + std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { + if( !m_floatingArg.get() ) + return tokens; + std::vector unusedTokens; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + if( token.type == Parser::Token::Positional ) + m_floatingArg->boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + } + return unusedTokens; + } + + void validate() const + { + if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) + throw std::logic_error( "No options or arguments specified" ); + + for( typename std::vector::const_iterator it = m_options.begin(), + itEnd = m_options.end(); + it != itEnd; ++it ) + it->validate(); + } + + private: + Detail::BoundArgFunction m_boundProcessName; + std::vector m_options; + std::map m_positionalArgs; + ArgAutoPtr m_floatingArg; + int m_highestSpecifiedArgPosition; + bool m_throwOnUnrecognisedTokens; + }; + +} // end namespace Clara + +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE + +#endif // TWOBLUECUBES_CLARA_H_INCLUDED +#undef STITCH_CLARA_OPEN_NAMESPACE + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#include + +namespace Catch { + + inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } + inline void abortAfterX( ConfigData& config, int x ) { + if( x < 1 ) + throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); + config.abortAfter = x; + } + inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + + inline void addWarning( ConfigData& config, std::string const& _warning ) { + if( _warning == "NoAssertions" ) + config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); + else + throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); + } + inline void setOrder( ConfigData& config, std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); + } + inline void setRngSeed( ConfigData& config, std::string const& seed ) { + if( seed == "time" ) { + config.rngSeed = static_cast( std::time(0) ); + } + else { + std::stringstream ss; + ss << seed; + ss >> config.rngSeed; + if( ss.fail() ) + throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); + } + } + inline void setVerbosity( ConfigData& config, int level ) { + // !TBD: accept strings? + config.verbosity = static_cast( level ); + } + inline void setShowDurations( ConfigData& config, bool _showDurations ) { + config.showDurations = _showDurations + ? ShowDurations::Always + : ShowDurations::Never; + } + inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { + std::ifstream f( _filename.c_str() ); + if( !f.is_open() ) + throw std::domain_error( "Unable to load input file: " + _filename ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, "#" ) ) + addTestOrTags( config, "\"" + line + "\"," ); + } + } + + inline Clara::CommandLine makeCommandLineParser() { + + using namespace Clara; + CommandLine cli; + + cli.bindProcessName( &ConfigData::processName ); + + cli["-?"]["-h"]["--help"] + .describe( "display usage information" ) + .bind( &ConfigData::showHelp ); + + cli["-l"]["--list-tests"] + .describe( "list all/matching test cases" ) + .bind( &ConfigData::listTests ); + + cli["-t"]["--list-tags"] + .describe( "list all/matching tags" ) + .bind( &ConfigData::listTags ); + + cli["-s"]["--success"] + .describe( "include successful tests in output" ) + .bind( &ConfigData::showSuccessfulTests ); + + cli["-b"]["--break"] + .describe( "break into debugger on failure" ) + .bind( &ConfigData::shouldDebugBreak ); + + cli["-e"]["--nothrow"] + .describe( "skip exception tests" ) + .bind( &ConfigData::noThrow ); + + cli["-i"]["--invisibles"] + .describe( "show invisibles (tabs, newlines)" ) + .bind( &ConfigData::showInvisibles ); + + cli["-o"]["--out"] + .describe( "output filename" ) + .bind( &ConfigData::outputFilename, "filename" ); + + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .describe( "reporter to use (defaults to console)" ) + .bind( &ConfigData::reporterName, "name" ); + + cli["-n"]["--name"] + .describe( "suite name" ) + .bind( &ConfigData::name, "name" ); + + cli["-a"]["--abort"] + .describe( "abort at first failure" ) + .bind( &abortAfterFirst ); + + cli["-x"]["--abortx"] + .describe( "abort after x failures" ) + .bind( &abortAfterX, "no. failures" ); + + cli["-w"]["--warn"] + .describe( "enable warnings" ) + .bind( &addWarning, "warning name" ); + +// - needs updating if reinstated +// cli.into( &setVerbosity ) +// .describe( "level of verbosity (0=no output)" ) +// .shortOpt( "v") +// .longOpt( "verbosity" ) +// .placeholder( "level" ); + + cli[_] + .describe( "which test or tests to use" ) + .bind( &addTestOrTags, "test name, pattern or tags" ); + + cli["-d"]["--durations"] + .describe( "show test durations" ) + .bind( &setShowDurations, "yes/no" ); + + cli["-f"]["--input-file"] + .describe( "load test names to run from a file" ) + .bind( &loadTestNamesFromFile, "filename" ); + + // Less common commands which don't have a short form + cli["--list-test-names-only"] + .describe( "list all/matching test cases names only" ) + .bind( &ConfigData::listTestNamesOnly ); + + cli["--list-reporters"] + .describe( "list all reporters" ) + .bind( &ConfigData::listReporters ); + + cli["--order"] + .describe( "test case order (defaults to decl)" ) + .bind( &setOrder, "decl|lex|rand" ); + + cli["--rng-seed"] + .describe( "set a specific seed for random numbers" ) + .bind( &setRngSeed, "'time'|number" ); + + cli["--force-colour"] + .describe( "force colourised output" ) + .bind( &ConfigData::forceColour ); + + return cli; + } + +} // end namespace Catch + +// #included from: internal/catch_list.hpp +#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED + +// #included from: catch_text.h +#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +// #included from: ../external/tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE + +namespace Catch { + using Tbc::Text; + using Tbc::TextAttributes; +} + +// #included from: catch_console_colour.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED + +namespace Catch { + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + + // By intention + FileName = LightGrey, + Warning = Yellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = Yellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour const& other ); + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved; + }; + + inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } + +} // end namespace Catch + +// #included from: catch_interfaces_reporter.h +#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED + +#include +#include +#include +#include + +namespace Catch +{ + struct ReporterConfig { + explicit ReporterConfig( Ptr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& stream() const { return *m_stream; } + Ptr fullConfig() const { return m_fullConfig; } + + private: + std::ostream* m_stream; + Ptr m_fullConfig; + }; + + struct ReporterPreferences { + ReporterPreferences() + : shouldRedirectStdOut( false ) + {} + + bool shouldRedirectStdOut; + }; + + template + struct LazyStat : Option { + LazyStat() : used( false ) {} + LazyStat& operator=( T const& _value ) { + Option::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option::reset(); + used = false; + } + bool used; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ) : name( _name ) {} + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + virtual ~AssertionStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; +# endif + + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + virtual ~SectionStats(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; +# endif + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + virtual ~TestCaseStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; +# endif + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + virtual ~TestGroupStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; +# endif + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + virtual ~TestRunStats(); + +# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestRunStats( TestRunStats const& _other ) + : runInfo( _other.runInfo ), + totals( _other.totals ), + aborting( _other.aborting ) + {} +# else + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; +# endif + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct IStreamingReporter : IShared { + virtual ~IStreamingReporter(); + + // Implementing class must also provide the following static method: + // static std::string getDescription(); + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + }; + + struct IReporterFactory { + virtual ~IReporterFactory(); + virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + + struct IReporterRegistry { + typedef std::map FactoryMap; + + virtual ~IReporterRegistry(); + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + }; + +} + +#include +#include + +namespace Catch { + + inline std::size_t listTests( Config const& config ) { + + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::size_t matchedTests = 0; + TextAttributes nameAttr, tagsAttr; + nameAttr.setInitialIndent( 2 ).setIndent( 4 ); + tagsAttr.setIndent( 6 ); + + std::vector matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } + + if( !config.testSpec().hasFilters() ) + Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; + else + Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; + return matchedTests; + } + + inline std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( !config.testSpec().hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + std::size_t matchedTests = 0; + std::vector matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Catch::cout() << testCaseInfo.name << std::endl; + } + return matchedTests; + } + + struct TagInfo { + TagInfo() : count ( 0 ) {} + void add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + std::string all() const { + std::string out; + for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); + it != itEnd; + ++it ) + out += "[" + *it + "]"; + return out; + } + std::set spellings; + std::size_t count; + }; + + inline std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::map tagCounts; + + std::vector matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::string lcaseTagName = toLower( tagName ); + std::map::iterator countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( std::map::const_iterator countIt = tagCounts.begin(), + countItEnd = tagCounts.end(); + countIt != countItEnd; + ++countIt ) { + std::ostringstream oss; + oss << " " << std::setw(2) << countIt->second.count << " "; + Text wrapper( countIt->second.all(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( oss.str().size() ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); + Catch::cout() << oss.str() << wrapper << "\n"; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; + return tagCounts.size(); + } + + inline std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; + std::size_t maxNameLen = 0; + for(it = itBegin; it != itEnd; ++it ) + maxNameLen = (std::max)( maxNameLen, it->first.size() ); + + for(it = itBegin; it != itEnd; ++it ) { + Text wrapper( it->second->getDescription(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( 7+maxNameLen ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); + Catch::cout() << " " + << it->first + << ":" + << std::string( maxNameLen - it->first.size() + 2, ' ' ) + << wrapper << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + inline Option list( Config const& config ) { + Option listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch + +// #included from: internal/catch_runner_impl.hpp +#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED + +// #included from: catch_test_case_tracker.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { +namespace SectionTracking { + + class TrackedSection { + + typedef std::map TrackedSections; + + public: + enum RunState { + NotStarted, + Executing, + ExecutingChildren, + Completed + }; + + TrackedSection( std::string const& name, TrackedSection* parent ) + : m_name( name ), m_runState( NotStarted ), m_parent( parent ) + {} + + RunState runState() const { return m_runState; } + + TrackedSection* findChild( std::string const& childName ); + TrackedSection* acquireChild( std::string const& childName ); + + void enter() { + if( m_runState == NotStarted ) + m_runState = Executing; + } + void leave(); + + TrackedSection* getParent() { + return m_parent; + } + bool hasChildren() const { + return !m_children.empty(); + } + + private: + std::string m_name; + RunState m_runState; + TrackedSections m_children; + TrackedSection* m_parent; + }; + + inline TrackedSection* TrackedSection::findChild( std::string const& childName ) { + TrackedSections::iterator it = m_children.find( childName ); + return it != m_children.end() + ? &it->second + : NULL; + } + inline TrackedSection* TrackedSection::acquireChild( std::string const& childName ) { + if( TrackedSection* child = findChild( childName ) ) + return child; + m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); + return findChild( childName ); + } + inline void TrackedSection::leave() { + for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); + it != itEnd; + ++it ) + if( it->second.runState() != Completed ) { + m_runState = ExecutingChildren; + return; + } + m_runState = Completed; + } + + class TestCaseTracker { + public: + TestCaseTracker( std::string const& testCaseName ) + : m_testCase( testCaseName, NULL ), + m_currentSection( &m_testCase ), + m_completedASectionThisRun( false ) + {} + + bool enterSection( std::string const& name ) { + TrackedSection* child = m_currentSection->acquireChild( name ); + if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed ) + return false; + + m_currentSection = child; + m_currentSection->enter(); + return true; + } + void leaveSection() { + m_currentSection->leave(); + m_currentSection = m_currentSection->getParent(); + assert( m_currentSection != NULL ); + m_completedASectionThisRun = true; + } + + bool currentSectionHasChildren() const { + return m_currentSection->hasChildren(); + } + bool isCompleted() const { + return m_testCase.runState() == TrackedSection::Completed; + } + + class Guard { + public: + Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) { + m_tracker.enterTestCase(); + } + ~Guard() { + m_tracker.leaveTestCase(); + } + private: + Guard( Guard const& ); + void operator = ( Guard const& ); + TestCaseTracker& m_tracker; + }; + + private: + void enterTestCase() { + m_currentSection = &m_testCase; + m_completedASectionThisRun = false; + m_testCase.enter(); + } + void leaveTestCase() { + m_testCase.leave(); + } + + TrackedSection m_testCase; + TrackedSection* m_currentSection; + bool m_completedASectionThisRun; + }; + +} // namespace SectionTracking + +using SectionTracking::TestCaseTracker; + +} // namespace Catch + +// #included from: catch_fatal_condition.hpp +#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED + +namespace Catch { + + // Report the error condition then exit the process + inline void fatal( std::string const& message, int exitCode ) { + IContext& context = Catch::getCurrentContext(); + IResultCapture* resultCapture = context.getResultCapture(); + resultCapture->handleFatalErrorCondition( message ); + + if( Catch::alwaysTrue() ) // avoids "no return" warnings + exit( exitCode ); + } + +} // namespace Catch + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { + + struct FatalConditionHandler { + void reset() {} + }; + +} // namespace Catch + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +#include + +namespace Catch { + + struct SignalDefs { int id; const char* name; }; + extern SignalDefs signalDefs[]; + SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + struct FatalConditionHandler { + + static void handleSignal( int sig ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + if( sig == signalDefs[i].id ) + fatal( signalDefs[i].name, -sig ); + fatal( "", -sig ); + } + + FatalConditionHandler() : m_isSet( true ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, handleSignal ); + } + ~FatalConditionHandler() { + reset(); + } + void reset() { + if( m_isSet ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, SIG_DFL ); + m_isSet = false; + } + } + + bool m_isSet; + }; + +} // namespace Catch + +#endif // not Windows + +#include +#include + +namespace Catch { + + class StreamRedirect { + + public: + StreamRedirect( std::ostream& stream, std::string& targetString ) + : m_stream( stream ), + m_prevBuf( stream.rdbuf() ), + m_targetString( targetString ) + { + stream.rdbuf( m_oss.rdbuf() ); + } + + ~StreamRedirect() { + m_targetString += m_oss.str(); + m_stream.rdbuf( m_prevBuf ); + } + + private: + std::ostream& m_stream; + std::streambuf* m_prevBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + RunContext( RunContext const& ); + void operator =( RunContext const& ); + + public: + + explicit RunContext( Ptr const& config, Ptr const& reporter ) + : m_runInfo( config->name() ), + m_context( getCurrentMutableContext() ), + m_activeTestCase( NULL ), + m_config( config ), + m_reporter( reporter ), + m_prevRunner( m_context.getRunner() ), + m_prevResultCapture( m_context.getResultCapture() ), + m_prevConfig( m_context.getConfig() ) + { + m_context.setRunner( this ); + m_context.setConfig( m_config ); + m_context.setResultCapture( this ); + m_reporter->testRunStarting( m_runInfo ); + } + + virtual ~RunContext() { + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); + m_context.setRunner( m_prevRunner ); + m_context.setConfig( NULL ); + m_context.setResultCapture( m_prevResultCapture ); + m_context.setConfig( m_prevConfig ); + } + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); + } + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); + } + + Totals runTest( TestCase const& testCase ) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + TestCaseInfo testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting( testInfo ); + + m_activeTestCase = &testCase; + m_testCaseTracker = TestCaseTracker( testInfo.name ); + + do { + do { + runCurrentTest( redirectedCout, redirectedCerr ); + } + while( !m_testCaseTracker->isCompleted() && !aborting() ); + } + while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); + + Totals deltaTotals = m_totals.delta( prevTotals ); + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting() ) ); + + m_activeTestCase = NULL; + m_testCaseTracker.reset(); + + return deltaTotals; + } + + Ptr config() const { + return m_config; + } + + private: // IResultCapture + + virtual void assertionEnded( AssertionResult const& result ) { + if( result.getResultType() == ResultWas::Ok ) { + m_totals.assertions.passed++; + } + else if( !result.isOk() ) { + m_totals.assertions.failed++; + } + + if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) + m_messages.clear(); + + // Reset working state + m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); + m_lastResult = result; + } + + virtual bool sectionStarted ( + SectionInfo const& sectionInfo, + Counts& assertions + ) + { + std::ostringstream oss; + oss << sectionInfo.name << "@" << sectionInfo.lineInfo; + + if( !m_testCaseTracker->enterSection( oss.str() ) ) + return false; + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting( sectionInfo ); + + assertions = m_totals.assertions; + + return true; + } + bool testForMissingAssertions( Counts& assertions ) { + if( assertions.total() != 0 || + !m_config->warnAboutMissingAssertions() || + m_testCaseTracker->currentSectionHasChildren() ) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) { + if( std::uncaught_exception() ) { + m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) ); + return; + } + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + m_testCaseTracker->leaveSection(); + + m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) ); + m_messages.clear(); + } + + virtual void pushScopedMessage( MessageInfo const& message ) { + m_messages.push_back( message ); + } + + virtual void popScopedMessage( MessageInfo const& message ) { + m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); + } + + virtual std::string getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : ""; + } + + virtual const AssertionResult* getLastResult() const { + return &m_lastResult; + } + + virtual void handleFatalErrorCondition( std::string const& message ) { + ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); + resultBuilder.setResultType( ResultWas::FatalErrorCondition ); + resultBuilder << message; + resultBuilder.captureExpression(); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); + m_reporter->sectionEnded( testCaseSectionStats ); + + TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + "", + "", + false ) ); + m_totals.testCases.failed++; + testGroupEnded( "", m_totals, 1, 1 ); + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); + } + + public: + // !TBD We need to do this another way! + bool aborting() const { + return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); + } + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + m_reporter->sectionStarting( testCaseSection ); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + try { + m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); + TestCaseTracker::Guard guard( *m_testCaseTracker ); + + Timer timer; + timer.start(); + if( m_reporter->getPreferences().shouldRedirectStdOut ) { + StreamRedirect coutRedir( Catch::cout(), redirectedCout ); + StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + invokeActiveTestCase(); + } + else { + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } + catch( TestFailureException& ) { + // This just means the test was aborted due to failure + } + catch(...) { + makeUnexpectedResultBuilder().useActiveException(); + } + handleUnfinishedSections(); + m_messages.clear(); + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( testCaseInfo.okToFail() ) { + std::swap( assertions.failedButOk, assertions.failed ); + m_totals.assertions.failed -= assertions.failedButOk; + m_totals.assertions.failedButOk += assertions.failedButOk; + } + + SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); + m_reporter->sectionEnded( testCaseSectionStats ); + } + + void invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + private: + + ResultBuilder makeUnexpectedResultBuilder() const { + return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression.c_str(), + m_lastAssertionInfo.resultDisposition ); + } + + void handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it ) + sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); + m_unfinishedSections.clear(); + } + + struct UnfinishedSections { + UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) + : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo info; + Counts prevAssertions; + double durationInSeconds; + }; + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase; + Option m_testCaseTracker; + AssertionResult m_lastResult; + + Ptr m_config; + Totals m_totals; + Ptr m_reporter; + std::vector m_messages; + IRunner* m_prevRunner; + IResultCapture* m_prevResultCapture; + Ptr m_prevConfig; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + }; + + IResultCapture& getResultCapture() { + if( IResultCapture* capture = getCurrentContext().getResultCapture() ) + return *capture; + else + throw std::logic_error( "No result capture instance" ); + } + +} // end namespace Catch + +// #included from: internal/catch_version.h +#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED + +namespace Catch { + + // Versioning information + struct Version { + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ); + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + std::string const branchName; + unsigned int const buildNumber; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); + + private: + void operator=( Version const& ); + }; + + extern Version libraryVersion; +} + +#include +#include +#include + +namespace Catch { + + class Runner { + + public: + Runner( Ptr const& config ) + : m_config( config ) + { + openStream(); + makeReporter(); + } + + Totals runTests() { + + RunContext context( m_config.get(), m_reporter ); + + Totals totals; + + context.testGroupStarting( "all tests", 1, 1 ); // deprecated? + + TestSpec testSpec = m_config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector testCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases ); + + int testsRunForGroup = 0; + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) { + testsRunForGroup++; + if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { + + if( context.aborting() ) + break; + + totals += context.runTest( *it ); + m_testsAlreadyRun.insert( *it ); + } + } + std::vector skippedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true ); + + for( std::vector::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end(); + it != itEnd; + ++it ) + m_reporter->skipTest( *it ); + + context.testGroupEnded( "all tests", totals, 1, 1 ); + return totals; + } + + private: + void openStream() { + // Open output file, if specified + if( !m_config->getFilename().empty() ) { + m_ofs.open( m_config->getFilename().c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << m_config->getFilename() << "'"; + throw std::domain_error( oss.str() ); + } + m_config->setStreamBuf( m_ofs.rdbuf() ); + } + } + void makeReporter() { + std::string reporterName = m_config->getReporterName().empty() + ? "console" + : m_config->getReporterName(); + + m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() ); + if( !m_reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + } + + private: + Ptr m_config; + std::ofstream m_ofs; + Ptr m_reporter; + std::set m_testsAlreadyRun; + }; + + class Session : NonCopyable { + static bool alreadyInstantiated; + + public: + + struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; + + Session() + : m_cli( makeCommandLineParser() ) { + if( alreadyInstantiated ) { + std::string msg = "Only one instance of Catch::Session can ever be used"; + Catch::cerr() << msg << std::endl; + throw std::logic_error( msg ); + } + alreadyInstantiated = true; + } + ~Session() { + Catch::cleanUp(); + } + + void showHelp( std::string const& processName ) { + Catch::cout() << "\nCatch v" << libraryVersion << "\n"; + + m_cli.usage( Catch::cout(), processName ); + Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; + } + + int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + try { + m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); + m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); + if( m_configData.showHelp ) + showHelp( m_configData.processName ); + m_config.reset(); + } + catch( std::exception& ex ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; + } + m_cli.usage( Catch::cout(), m_configData.processName ); + return (std::numeric_limits::max)(); + } + return 0; + } + + void useConfigData( ConfigData const& _configData ) { + m_configData = _configData; + m_config.reset(); + } + + int run( int argc, char* const argv[] ) { + + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + + int run() { + if( m_configData.showHelp ) + return 0; + + try + { + config(); // Force config to be constructed + + std::srand( m_configData.rngSeed ); + + Runner runner( m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + return static_cast( runner.runTests().assertions.failed ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return (std::numeric_limits::max)(); + } + } + + Clara::CommandLine const& cli() const { + return m_cli; + } + std::vector const& unusedTokens() const { + return m_unusedTokens; + } + ConfigData& configData() { + return m_configData; + } + Config& config() { + if( !m_config ) + m_config = new Config( m_configData ); + return *m_config; + } + + private: + Clara::CommandLine m_cli; + std::vector m_unusedTokens; + ConfigData m_configData; + Ptr m_config; + }; + + bool Session::alreadyInstantiated = false; + +} // end namespace Catch + +// #included from: catch_registry_hub.hpp +#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED + +// #included from: catch_test_case_registry_impl.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED + +#include +#include +#include +#include +#include + +namespace Catch { + + class TestRegistry : public ITestCaseRegistry { + struct LexSort { + bool operator() (TestCase i,TestCase j) const { return (i const& getAllTests() const { + return m_functionsInOrder; + } + + virtual std::vector const& getAllNonHiddenTests() const { + return m_nonHiddenFunctions; + } + + virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const { + + for( std::vector::const_iterator it = m_functionsInOrder.begin(), + itEnd = m_functionsInOrder.end(); + it != itEnd; + ++it ) { + bool includeTest = testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ); + if( includeTest != negated ) + matchingTestCases.push_back( *it ); + } + sortTests( config, matchingTestCases ); + } + + private: + + static void sortTests( IConfig const& config, std::vector& matchingTestCases ) { + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + RandomNumberGenerator rng; + std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + } + std::set m_functions; + std::vector m_functionsInOrder; + std::vector m_nonHiddenFunctions; + size_t m_unnamedCount; + }; + + /////////////////////////////////////////////////////////////////////////// + + class FreeFunctionTestCase : public SharedImpl { + public: + + FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} + + virtual void invoke() const { + m_fun(); + } + + private: + virtual ~FreeFunctionTestCase(); + + TestFunction m_fun; + }; + + inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, "&" ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + + /////////////////////////////////////////////////////////////////////////// + + AutoReg::AutoReg( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + } + + AutoReg::~AutoReg() {} + + void AutoReg::registerTestCase( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + getMutableRegistryHub().registerTest + ( makeTestCase( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + +} // end namespace Catch + +// #included from: catch_reporter_registry.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED + +#include + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + virtual ~ReporterRegistry() { + deleteAllValues( m_factories ); + } + + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const { + FactoryMap::const_iterator it = m_factories.find( name ); + if( it == m_factories.end() ) + return NULL; + return it->second->create( ReporterConfig( config ) ); + } + + void registerReporter( std::string const& name, IReporterFactory* factory ) { + m_factories.insert( std::make_pair( name, factory ) ); + } + + FactoryMap const& getFactories() const { + return m_factories; + } + + private: + FactoryMap m_factories; + }; +} + +// #included from: catch_exception_translator_registry.hpp +#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED + +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry() { + deleteAll( m_translators ); + } + + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( translator ); + } + + virtual std::string translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + throw; + } + @catch (NSException *exception) { + return Catch::toString( [exception description] ); + } +#else + throw; +#endif + } + catch( TestFailureException& ) { + throw; + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return tryTranslators( m_translators.begin() ); + } + } + + std::string tryTranslators( std::vector::const_iterator it ) const { + if( it == m_translators.end() ) + return "Unknown exception"; + + try { + return (*it)->translate(); + } + catch(...) { + return tryTranslators( it+1 ); + } + } + + private: + std::vector m_translators; + }; +} + +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub { + + RegistryHub( RegistryHub const& ); + void operator=( RegistryHub const& ); + + public: // IRegistryHub + RegistryHub() { + } + virtual IReporterRegistry const& getReporterRegistry() const { + return m_reporterRegistry; + } + virtual ITestCaseRegistry const& getTestCaseRegistry() const { + return m_testCaseRegistry; + } + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() { + return m_exceptionTranslatorRegistry; + } + + public: // IMutableRegistryHub + virtual void registerReporter( std::string const& name, IReporterFactory* factory ) { + m_reporterRegistry.registerReporter( name, factory ); + } + virtual void registerTest( TestCase const& testInfo ) { + m_testCaseRegistry.registerTest( testInfo ); + } + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + }; + + // Single, global, instance + inline RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = NULL; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = NULL; + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch + +// #included from: catch_notimplemented_exception.hpp +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED + +#include + +namespace Catch { + + NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) + : m_lineInfo( lineInfo ) { + std::ostringstream oss; + oss << lineInfo << ": function "; + oss << "not implemented"; + m_what = oss.str(); + } + + const char* NotImplementedException::what() const CATCH_NOEXCEPT { + return m_what.c_str(); + } + +} // end namespace Catch + +// #included from: catch_context_impl.hpp +#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED + +// #included from: catch_stream.hpp +#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED + +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED + +#include + +namespace Catch { + + class StreamBufBase : public std::streambuf { + public: + virtual ~StreamBufBase() CATCH_NOEXCEPT; + }; +} + +#include +#include +#include + +namespace Catch { + + template + class StreamBufImpl : public StreamBufBase { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() CATCH_NOEXCEPT { + sync(); + } + + private: + int overflow( int c ) { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; + } + + int sync() { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + Stream::Stream() + : streamBuf( NULL ), isOwned( false ) + {} + + Stream::Stream( std::streambuf* _streamBuf, bool _isOwned ) + : streamBuf( _streamBuf ), isOwned( _isOwned ) + {} + + void Stream::release() { + if( isOwned ) { + delete streamBuf; + streamBuf = NULL; + isOwned = false; + } + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions + std::ostream& cout() { + return std::cout; + } + std::ostream& cerr() { + return std::cerr; + } +#endif +} + +namespace Catch { + + class Context : public IMutableContext { + + Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {} + Context( Context const& ); + void operator=( Context const& ); + + public: // IContext + virtual IResultCapture* getResultCapture() { + return m_resultCapture; + } + virtual IRunner* getRunner() { + return m_runner; + } + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { + return getGeneratorsForCurrentTest() + .getGeneratorInfo( fileInfo, totalSize ) + .getCurrentIndex(); + } + virtual bool advanceGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + return generators && generators->moveNext(); + } + + virtual Ptr getConfig() const { + return m_config; + } + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) { + m_runner = runner; + } + virtual void setConfig( Ptr const& config ) { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IGeneratorsForTest* findGeneratorsForCurrentTest() { + std::string testName = getResultCapture()->getCurrentTestName(); + + std::map::const_iterator it = + m_generatorsByTestName.find( testName ); + return it != m_generatorsByTestName.end() + ? it->second + : NULL; + } + + IGeneratorsForTest& getGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + if( !generators ) { + std::string testName = getResultCapture()->getCurrentTestName(); + generators = createGeneratorsForTest(); + m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); + } + return *generators; + } + + private: + Ptr m_config; + IRunner* m_runner; + IResultCapture* m_resultCapture; + std::map m_generatorsByTestName; + }; + + namespace { + Context* currentContext = NULL; + } + IMutableContext& getCurrentMutableContext() { + if( !currentContext ) + currentContext = new Context(); + return *currentContext; + } + IContext& getCurrentContext() { + return getCurrentMutableContext(); + } + + Stream createStream( std::string const& streamName ) { + if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false ); + if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false ); + if( streamName == "debug" ) return Stream( new StreamBufImpl, true ); + + throw std::domain_error( "Unknown stream: " + streamName ); + } + + void cleanUpContext() { + delete currentContext; + currentContext = NULL; + } +} + +// #included from: catch_console_colour_impl.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() {} + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalAttributes = csbiInfo.wAttributes; + } + + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute ); + } + HANDLE stdoutHandle; + WORD originalAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + return &s_instance; + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0:34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + Catch::cout() << '\033' << _escapeCode; + } + }; + + IColourImpl* platformColourInstance() { + Ptr config = getCurrentContext().getConfig(); + return (config && config->forceColour()) || isatty(STDOUT_FILENO) + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } + Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = isDebuggerActive() + ? NoColourImpl::instance() + : platformColourInstance(); + impl->use( _colourCode ); + } + +} // end namespace Catch + +// #included from: catch_generators_impl.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct GeneratorInfo : IGeneratorInfo { + + GeneratorInfo( std::size_t size ) + : m_size( size ), + m_currentIndex( 0 ) + {} + + bool moveNext() { + if( ++m_currentIndex == m_size ) { + m_currentIndex = 0; + return false; + } + return true; + } + + std::size_t getCurrentIndex() const { + return m_currentIndex; + } + + std::size_t m_size; + std::size_t m_currentIndex; + }; + + /////////////////////////////////////////////////////////////////////////// + + class GeneratorsForTest : public IGeneratorsForTest { + + public: + ~GeneratorsForTest() { + deleteAll( m_generatorsInOrder ); + } + + IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { + std::map::const_iterator it = m_generatorsByName.find( fileInfo ); + if( it == m_generatorsByName.end() ) { + IGeneratorInfo* info = new GeneratorInfo( size ); + m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); + m_generatorsInOrder.push_back( info ); + return *info; + } + return *it->second; + } + + bool moveNext() { + std::vector::const_iterator it = m_generatorsInOrder.begin(); + std::vector::const_iterator itEnd = m_generatorsInOrder.end(); + for(; it != itEnd; ++it ) { + if( (*it)->moveNext() ) + return true; + } + return false; + } + + private: + std::map m_generatorsByName; + std::vector m_generatorsInOrder; + }; + + IGeneratorsForTest* createGeneratorsForTest() + { + return new GeneratorsForTest(); + } + +} // end namespace Catch + +// #included from: catch_assertionresult.hpp +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED + +namespace Catch { + + AssertionInfo::AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + capturedExpression( _capturedExpression ), + resultDisposition( _resultDisposition ) + {} + + AssertionResult::AssertionResult() {} + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + AssertionResult::~AssertionResult() {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return !m_info.capturedExpression.empty(); + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!" + m_info.capturedExpression; + else + return m_info.capturedExpression; + } + std::string AssertionResult::getExpressionInMacro() const { + if( m_info.macroName.empty() ) + return m_info.capturedExpression; + else + return m_info.macroName + "( " + m_info.capturedExpression + " )"; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + return m_resultData.reconstructedExpression; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + std::string AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch + +// #included from: catch_test_case_info.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED + +namespace Catch { + + inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, "." ) || + tag == "hide" || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else + return TestCaseInfo::None; + } + inline bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); + } + inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + if( isReservedTag( tag ) ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "Tag name [" << tag << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n"; + } + { + Colour colourGuard( Colour::FileName ); + Catch::cerr() << _lineInfo << std::endl; + } + exit(1); + } + } + + TestCase makeTestCase( ITestCase* _testCase, + std::string const& _className, + std::string const& _name, + std::string const& _descOrTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden( startsWith( _name, "./" ) ); // Legacy support + + // Parse out tags + std::set tags; + std::string desc, tag; + bool inTag = false; + for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { + char c = _descOrTags[i]; + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( prop == TestCaseInfo::IsHidden ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.insert( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.insert( "hide" ); + tags.insert( "." ); + } + + TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, info ); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + tags( _tags ), + lineInfo( _lineInfo ), + properties( None ) + { + std::ostringstream oss; + for( std::set::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + properties = static_cast( properties | parseSpecialTag( lcaseTag ) ); + lcaseTags.insert( lcaseTag ); + } + tagsAsString = oss.str(); + } + + TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) + : name( other.name ), + className( other.className ), + description( other.description ), + tags( other.tags ), + lcaseTags( other.lcaseTags ), + tagsAsString( other.tagsAsString ), + lineInfo( other.lineInfo ), + properties( other.properties ) + {} + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + + TestCase::TestCase( TestCase const& other ) + : TestCaseInfo( other ), + test( other.test ) + {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::swap( TestCase& other ) { + test.swap( other.test ); + name.swap( other.name ); + className.swap( other.className ); + description.swap( other.description ); + tags.swap( other.tags ); + lcaseTags.swap( other.lcaseTags ); + tagsAsString.swap( other.tagsAsString ); + std::swap( TestCaseInfo::properties, static_cast( other ).properties ); + std::swap( lineInfo, other.lineInfo ); + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + TestCase& TestCase::operator = ( TestCase const& other ) { + TestCase temp( other ); + swap( temp ); + return *this; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch + +// #included from: catch_version.hpp +#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << "." + << version.minorVersion << "." + << version.patchNumber; + + if( !version.branchName.empty() ) { + os << "-" << version.branchName + << "." << version.buildNumber; + } + return os; + } + + Version libraryVersion( 1, 2, 1, "", 0 ); + +} + +// #included from: catch_message.hpp +#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED + +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + ScopedMessage::ScopedMessage( ScopedMessage const& other ) + : m_info( other.m_info ) + {} + + ScopedMessage::~ScopedMessage() { + getResultCapture().popScopedMessage( m_info ); + } + +} // end namespace Catch + +// #included from: catch_legacy_reporter_adapter.hpp +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED + +// #included from: catch_legacy_reporter_adapter.h +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED + +namespace Catch +{ + // Deprecated + struct IReporter : IShared { + virtual ~IReporter(); + + virtual bool shouldRedirectStdout() const = 0; + + virtual void StartTesting() = 0; + virtual void EndTesting( Totals const& totals ) = 0; + virtual void StartGroup( std::string const& groupName ) = 0; + virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; + virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; + virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; + virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; + virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; + virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; + virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; + virtual void Aborted() = 0; + virtual void Result( AssertionResult const& result ) = 0; + }; + + class LegacyReporterAdapter : public SharedImpl + { + public: + LegacyReporterAdapter( Ptr const& legacyReporter ); + virtual ~LegacyReporterAdapter(); + + virtual ReporterPreferences getPreferences() const; + virtual void noMatchingTestCases( std::string const& ); + virtual void testRunStarting( TestRunInfo const& ); + virtual void testGroupStarting( GroupInfo const& groupInfo ); + virtual void testCaseStarting( TestCaseInfo const& testInfo ); + virtual void sectionStarting( SectionInfo const& sectionInfo ); + virtual void assertionStarting( AssertionInfo const& ); + virtual bool assertionEnded( AssertionStats const& assertionStats ); + virtual void sectionEnded( SectionStats const& sectionStats ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ); + virtual void testGroupEnded( TestGroupStats const& testGroupStats ); + virtual void testRunEnded( TestRunStats const& testRunStats ); + virtual void skipTest( TestCaseInfo const& ); + + private: + Ptr m_legacyReporter; + }; +} + +namespace Catch +{ + LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) + : m_legacyReporter( legacyReporter ) + {} + LegacyReporterAdapter::~LegacyReporterAdapter() {} + + ReporterPreferences LegacyReporterAdapter::getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); + return prefs; + } + + void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} + void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { + m_legacyReporter->StartTesting(); + } + void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { + m_legacyReporter->StartGroup( groupInfo.name ); + } + void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { + m_legacyReporter->StartTestCase( testInfo ); + } + void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { + m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); + } + void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { + // Not on legacy interface + } + + bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); + rb << it->message; + rb.setResultType( ResultWas::Info ); + AssertionResult result = rb.build(); + m_legacyReporter->Result( result ); + } + } + } + m_legacyReporter->Result( assertionStats.assertionResult ); + return true; + } + void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { + if( sectionStats.missingAssertions ) + m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); + m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); + } + void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { + m_legacyReporter->EndTestCase + ( testCaseStats.testInfo, + testCaseStats.totals, + testCaseStats.stdOut, + testCaseStats.stdErr ); + } + void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { + if( testGroupStats.aborting ) + m_legacyReporter->Aborted(); + m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); + } + void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { + m_legacyReporter->EndTesting( testRunStats.totals ); + } + void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { + } +} + +// #included from: catch_timer.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif + +#ifdef CATCH_PLATFORM_WINDOWS +#include +#else +#include +#endif + +namespace Catch { + + namespace { +#ifdef CATCH_PLATFORM_WINDOWS + uint64_t getCurrentTicks() { + static uint64_t hz=0, hzo=0; + if (!hz) { + QueryPerformanceFrequency( reinterpret_cast( &hz ) ); + QueryPerformanceCounter( reinterpret_cast( &hzo ) ); + } + uint64_t t; + QueryPerformanceCounter( reinterpret_cast( &t ) ); + return ((t-hzo)*1000000)/hz; + } +#else + uint64_t getCurrentTicks() { + timeval t; + gettimeofday(&t,NULL); + return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); + } +#endif + } + + void Timer::start() { + m_ticks = getCurrentTicks(); + } + unsigned int Timer::getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); + } + unsigned int Timer::getElapsedMilliseconds() const { + return static_cast(getElapsedMicroseconds()/1000); + } + double Timer::getElapsedSeconds() const { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +// #included from: catch_common.hpp +#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << " " << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << "s"; + return os; + } + + SourceLineInfo::SourceLineInfo() : line( 0 ){} + SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) + : file( _file ), + line( _line ) + {} + SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) + : file( other.file ), + line( other.line ) + {} + bool SourceLineInfo::empty() const { + return file.empty(); + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { + return line == other.line && file == other.file; + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { + return line < other.line || ( line == other.line && file < other.file ); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << "(" << info.line << ")"; +#else + os << info.file << ":" << info.line; +#endif + return os; + } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { + std::ostringstream oss; + oss << locationInfo << ": Internal Catch error: '" << message << "'"; + if( alwaysTrue() ) + throw std::logic_error( oss.str() ); + } +} + +// #included from: catch_section.hpp +#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) + getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() ); + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch + +// #included from: catch_debugger.hpp +#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED + +#include + +#ifdef CATCH_PLATFORM_MAC + + #include + #include + #include + #include + #include + + namespace Catch{ + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + inline bool isDebuggerActive() { return false; } + } +#endif // Platform + +#ifdef CATCH_PLATFORM_WINDOWS + extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } +#else + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } +#endif // Platform + +// #included from: catch_tostring.hpp +#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED + +namespace Catch { + +namespace Detail { + + std::string unprintableString = "{?}"; + + namespace { + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) + { + // Reverse order for little endian architectures + int i = 0, end = static_cast( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + os << std::setw(2) << static_cast(bytes[i]); + return os.str(); + } +} + +std::string toString( std::string const& value ) { + std::string s = value; + if( getCurrentContext().getConfig()->showInvisibles() ) { + for(size_t i = 0; i < s.size(); ++i ) { + std::string subs; + switch( s[i] ) { + case '\n': subs = "\\n"; break; + case '\t': subs = "\\t"; break; + default: break; + } + if( !subs.empty() ) { + s = s.substr( 0, i ) + subs + s.substr( i+1 ); + ++i; + } + } + } + return "\"" + s + "\""; +} +std::string toString( std::wstring const& value ) { + + std::string s; + s.reserve( value.size() ); + for(size_t i = 0; i < value.size(); ++i ) + s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; + return Catch::toString( s ); +} + +std::string toString( const char* const value ) { + return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); +} + +std::string toString( char* const value ) { + return Catch::toString( static_cast( value ) ); +} + +std::string toString( const wchar_t* const value ) +{ + return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); +} + +std::string toString( wchar_t* const value ) +{ + return Catch::toString( static_cast( value ) ); +} + +std::string toString( int value ) { + std::ostringstream oss; + oss << value; + if( value >= 255 ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned long value ) { + std::ostringstream oss; + oss << value; + if( value >= 255 ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned int value ) { + return Catch::toString( static_cast( value ) ); +} + +template +std::string fpToString( T value, int precision ) { + std::ostringstream oss; + oss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = oss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +std::string toString( const double value ) { + return fpToString( value, 10 ); +} +std::string toString( const float value ) { + return fpToString( value, 5 ) + "f"; +} + +std::string toString( bool value ) { + return value ? "true" : "false"; +} + +std::string toString( char value ) { + return value < ' ' + ? toString( static_cast( value ) ) + : Detail::makeString( value ); +} + +std::string toString( signed char value ) { + return toString( static_cast( value ) ); +} + +std::string toString( unsigned char value ) { + return toString( static_cast( value ) ); +} + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ) { + return "nullptr"; +} +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSObject* const& nsObject ) { + return toString( [nsObject description] ); + } +#endif + +} // end namespace Catch + +// #included from: catch_result_builder.hpp +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED + +namespace Catch { + + ResultBuilder::ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition ) + : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ), + m_shouldDebugBreak( false ), + m_shouldThrow( false ) + {} + + ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { + m_data.resultType = result; + return *this; + } + ResultBuilder& ResultBuilder::setResultType( bool result ) { + m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; + return *this; + } + ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { + m_exprComponents.lhs = lhs; + return *this; + } + ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { + m_exprComponents.rhs = rhs; + return *this; + } + ResultBuilder& ResultBuilder::setOp( std::string const& op ) { + m_exprComponents.op = op; + return *this; + } + + void ResultBuilder::endExpression() { + m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); + captureExpression(); + } + + void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + m_stream.oss << Catch::translateActiveException(); + captureResult( ResultWas::ThrewException ); + } + + void ResultBuilder::captureResult( ResultWas::OfType resultType ) { + setResultType( resultType ); + captureExpression(); + } + + void ResultBuilder::captureExpression() { + AssertionResult result = build(); + getResultCapture().assertionEnded( result ); + + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) + m_shouldThrow = true; + } + } + void ResultBuilder::react() { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } + bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } + + AssertionResult ResultBuilder::build() const + { + assert( m_data.resultType != ResultWas::Unknown ); + + AssertionResultData data = m_data; + + // Flip bool results if testFalse is set + if( m_exprComponents.testFalse ) { + if( data.resultType == ResultWas::Ok ) + data.resultType = ResultWas::ExpressionFailed; + else if( data.resultType == ResultWas::ExpressionFailed ) + data.resultType = ResultWas::Ok; + } + + data.message = m_stream.oss.str(); + data.reconstructedExpression = reconstructExpression(); + if( m_exprComponents.testFalse ) { + if( m_exprComponents.op == "" ) + data.reconstructedExpression = "!" + data.reconstructedExpression; + else + data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; + } + return AssertionResult( m_assertionInfo, data ); + } + std::string ResultBuilder::reconstructExpression() const { + if( m_exprComponents.op == "" ) + return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; + else if( m_exprComponents.op == "matches" ) + return m_exprComponents.lhs + " " + m_exprComponents.rhs; + else if( m_exprComponents.op != "!" ) { + if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && + m_exprComponents.lhs.find("\n") == std::string::npos && + m_exprComponents.rhs.find("\n") == std::string::npos ) + return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; + else + return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; + } + else + return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; + } + +} // end namespace Catch + +// #included from: catch_tag_alias_registry.hpp +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED + +// #included from: catch_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + +#include + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + virtual ~TagAliasRegistry(); + virtual Option find( std::string const& alias ) const; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; + void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + static TagAliasRegistry& get(); + + private: + std::map m_registry; + }; + +} // end namespace Catch + +#include +#include + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + Option TagAliasRegistry::find( std::string const& alias ) const { + std::map::const_iterator it = m_registry.find( alias ); + if( it != m_registry.end() ) + return it->second; + else + return Option(); + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); + it != itEnd; + ++it ) { + std::size_t pos = expandedTestSpec.find( it->first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + it->second.tag + + expandedTestSpec.substr( pos + it->first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + + if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" already registered.\n" + << "\tFirst seen at " << find(alias)->lineInfo << "\n" + << "\tRedefined at " << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + } + + TagAliasRegistry& TagAliasRegistry::get() { + static TagAliasRegistry instance; + return instance; + + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } + + RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + try { + TagAliasRegistry::get().add( alias, tag, lineInfo ); + } + catch( std::exception& ex ) { + Colour colourGuard( Colour::Red ); + Catch::cerr() << ex.what() << std::endl; + exit(1); + } + } + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_xml.hpp +#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED + +// #included from: catch_reporter_bases.hpp +#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED + +#include + +namespace Catch { + + struct StreamingReporterBase : SharedImpl { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + {} + + virtual ~StreamingReporterBase(); + + virtual void noMatchingTestCases( std::string const& ) {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) { + currentTestRunInfo = _testRunInfo; + } + virtual void testGroupStarting( GroupInfo const& _groupInfo ) { + currentGroupInfo = _groupInfo; + } + + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) { + currentTestCaseInfo = _testInfo; + } + virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + m_sectionStack.push_back( _sectionInfo ); + } + + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) { + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { + currentTestCaseInfo.reset(); + } + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { + currentGroupInfo.reset(); + } + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + virtual void skipTest( TestCaseInfo const& ) { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + Ptr m_config; + std::ostream& stream; + + LazyStat currentTestRunInfo; + LazyStat currentGroupInfo; + LazyStat currentTestCaseInfo; + + std::vector m_sectionStack; + }; + + struct CumulativeReporterBase : SharedImpl { + template + struct Node : SharedImpl<> { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + typedef std::vector > ChildNodes; + T value; + ChildNodes children; + }; + struct SectionNode : SharedImpl<> { + explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} + virtual ~SectionNode(); + + bool operator == ( SectionNode const& other ) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == ( Ptr const& other ) const { + return operator==( *other ); + } + + SectionStats stats; + typedef std::vector > ChildSections; + typedef std::vector Assertions; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() ( Ptr const& node ) const { + return node->stats.sectionInfo.lineInfo == m_other.lineInfo; + } + private: + void operator=( BySectionInfo const& ); + SectionInfo const& m_other; + }; + + typedef Node TestCaseNode; + typedef Node TestGroupNode; + typedef Node TestRunNode; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + {} + ~CumulativeReporterBase(); + + virtual void testRunStarting( TestRunInfo const& ) {} + virtual void testGroupStarting( GroupInfo const& ) {} + + virtual void testCaseStarting( TestCaseInfo const& ) {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + Ptr node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = new SectionNode( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + SectionNode::ChildSections::const_iterator it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = new SectionNode( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = node; + } + + virtual void assertionStarting( AssertionInfo const& ) {} + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back( assertionStats ); + return true; + } + virtual void sectionEnded( SectionStats const& sectionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + Ptr node = new TestCaseNode( testCaseStats ); + assert( m_sectionStack.size() == 0 ); + node->children.push_back( m_rootSection ); + m_testCases.push_back( node ); + m_rootSection.reset(); + + assert( m_deepestSection ); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + Ptr node = new TestGroupNode( testGroupStats ); + node->children.swap( m_testCases ); + m_testGroups.push_back( node ); + } + virtual void testRunEnded( TestRunStats const& testRunStats ) { + Ptr node = new TestRunNode( testRunStats ); + node->children.swap( m_testGroups ); + m_testRuns.push_back( node ); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + virtual void skipTest( TestCaseInfo const& ) {} + + Ptr m_config; + std::ostream& stream; + std::vector m_assertions; + std::vector > > m_sections; + std::vector > m_testCases; + std::vector > m_testGroups; + + std::vector > m_testRuns; + + Ptr m_rootSection; + Ptr m_deepestSection; + std::vector > m_sectionStack; + + }; + + template + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + +} // end namespace Catch + +// #included from: ../internal/catch_reporter_registrars.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED + +namespace Catch { + + template + class LegacyReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new LegacyReporterAdapter( new T( config ) ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + LegacyReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + + // *** Please Note ***: + // - If you end up here looking at a compiler error because it's trying to register + // your custom reporter class be aware that the native reporter interface has changed + // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via + // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. + // However please consider updating to the new interface as the old one is now + // deprecated and will probably be removed quite soon! + // Please contact me via github if you have any questions at all about this. + // In fact, ideally, please contact me anyway to let me know you've hit this - as I have + // no idea who is actually using custom reporters at all (possibly no-one!). + // The new interface is designed to minimise exposure to interface changes in the future. + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; +} + +#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ + namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } +#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ + namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +// #included from: ../internal/catch_xmlwriter.hpp +#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + ScopedElement( ScopedElement const& other ) + : m_writer( other.m_writer ){ + other.m_writer = NULL; + } + + ~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + ScopedElement& writeText( std::string const& text, bool indent = true ) { + m_writer->writeText( text, indent ); + return *this; + } + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer; + }; + + XmlWriter() + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &Catch::cout() ) + {} + + XmlWriter( std::ostream& os ) + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &os ) + {} + + ~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + stream() << m_indent << "<" << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + ScopedElement scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + stream() << "/>\n"; + m_tagIsOpen = false; + } + else { + stream() << m_indent << "\n"; + } + m_tags.pop_back(); + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) { + stream() << " " << name << "=\""; + writeEncodedText( attribute ); + stream() << "\""; + } + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, bool attribute ) { + stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; + return *this; + } + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + if( !name.empty() ) + stream() << " " << name << "=\"" << attribute << "\""; + return *this; + } + + XmlWriter& writeText( std::string const& text, bool indent = true ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + stream() << m_indent; + writeEncodedText( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& writeComment( std::string const& text ) { + ensureTagClosed(); + stream() << m_indent << ""; + m_needsNewline = true; + return *this; + } + + XmlWriter& writeBlankLine() { + ensureTagClosed(); + stream() << "\n"; + return *this; + } + + void setStream( std::ostream& os ) { + m_os = &os; + } + + private: + XmlWriter( XmlWriter const& ); + void operator=( XmlWriter const& ); + + std::ostream& stream() { + return *m_os; + } + + void ensureTagClosed() { + if( m_tagIsOpen ) { + stream() << ">\n"; + m_tagIsOpen = false; + } + } + + void newlineIfNecessary() { + if( m_needsNewline ) { + stream() << "\n"; + m_needsNewline = false; + } + } + + void writeEncodedText( std::string const& text ) { + static const char* charsToEncode = "<&\""; + std::string mtext = text; + std::string::size_type pos = mtext.find_first_of( charsToEncode ); + while( pos != std::string::npos ) { + stream() << mtext.substr( 0, pos ); + + switch( mtext[pos] ) { + case '<': + stream() << "<"; + break; + case '&': + stream() << "&"; + break; + case '\"': + stream() << """; + break; + } + mtext = mtext.substr( pos+1 ); + pos = mtext.find_first_of( charsToEncode ); + } + stream() << mtext; + } + + bool m_tagIsOpen; + bool m_needsNewline; + std::vector m_tags; + std::string m_indent; + std::ostream* m_os; + }; + +} +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_sectionDepth( 0 ) + {} + + virtual ~XmlReporter(); + + static std::string getDescription() { + return "Reports test results as an XML document"; + } + + public: // StreamingReporterBase + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = true; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& s ) { + StreamingReporterBase::noMatchingTestCases( s ); + } + + virtual void testRunStarting( TestRunInfo const& testInfo ) { + StreamingReporterBase::testRunStarting( testInfo ); + m_xml.setStream( stream ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); + } + } + + virtual void assertionStarting( AssertionInfo const& ) { } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + const AssertionResult& assertionResult = assertionStats.assertionResult; + + // Print any info messages in tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + m_xml.scopedElement( "Info" ) + .writeText( it->message ); + } else if ( it->type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( it->message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) + return true; + + // Print the expression if there is one. + if( assertionResult.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", assertionResult.succeeded() ) + .writeAttribute( "type", assertionResult.getTestMacroName() ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ); + + m_xml.scopedElement( "Original" ) + .writeText( assertionResult.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( assertionResult.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( assertionResult.getResultType() ) { + case ResultWas::ThrewException: + m_xml.scopedElement( "Exception" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::FatalErrorCondition: + m_xml.scopedElement( "Fatal Error Condition" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.scopedElement( "Failure" ) + .writeText( assertionResult.getMessage() ); + break; + default: + break; + } + + if( assertionResult.hasExpression() ) + m_xml.endElement(); + + return true; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + m_xml.endElement(); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_junit.hpp +#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED + +#include + +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + {} + + ~JunitReporter(); + + static std::string getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + virtual void noMatchingTestCases( std::string const& /*spec*/ ) {} + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = true; + return prefs; + } + + virtual void testRunStarting( TestRunInfo const& runInfo ) { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) { + suiteTimer.start(); + stdOutForSuite.str(""); + stdErrForSuite.str(""); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + stdOutForSuite << testCaseStats.stdOut; + stdErrForSuite << testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + virtual void testRunEndedCumulative() { + xml.endElement(); + } + + void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", "tbd" ); // !TBD + + // Write test cases + for( TestGroupNode::ChildNodes::const_iterator + it = groupNode.children.begin(), itEnd = groupNode.children.end(); + it != itEnd; + ++it ) + writeTestCase( **it ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); + } + + void writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + if( rootSection.childSections.empty() ) + className = "global"; + } + writeSection( className, "", rootSection ); + } + + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + "/" + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( SectionNode::ChildSections::const_iterator + it = sectionNode.childSections.begin(), + itEnd = sectionNode.childSections.end(); + it != itEnd; + ++it ) + if( className.empty() ) + writeSection( name, "", **it ); + else + writeSection( className, name, **it ); + } + + void writeAssertions( SectionNode const& sectionNode ) { + for( SectionNode::Assertions::const_iterator + it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); + it != itEnd; + ++it ) + writeAssertion( *it ); + } + void writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + std::ostringstream oss; + if( !result.getMessage().empty() ) + oss << result.getMessage() << "\n"; + for( std::vector::const_iterator + it = stats.infoMessages.begin(), + itEnd = stats.infoMessages.end(); + it != itEnd; + ++it ) + if( it->type == ResultWas::Info ) + oss << it->message << "\n"; + + oss << "at " << result.getSourceInfo(); + xml.writeText( oss.str(), false ); + } + } + + XmlWriter xml; + Timer suiteTimer; + std::ostringstream stdOutForSuite; + std::ostringstream stdErrForSuite; + unsigned int unexpectedExceptions; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_console.hpp +#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED + +namespace Catch { + + struct ConsoleReporter : StreamingReporterBase { + ConsoleReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_headerPrinted( false ) + {} + + virtual ~ConsoleReporter(); + static std::string getDescription() { + return "Reports test results as plain lines of text"; + } + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + lazyPrint(); + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + stream << std::endl; + return true; + } + + virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting( _sectionInfo ); + } + virtual void sectionEnded( SectionStats const& _sectionStats ) { + if( _sectionStats.missingAssertions ) { + lazyPrint(); + Colour colour( Colour::ResultError ); + if( m_sectionStack.size() > 1 ) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if( m_headerPrinted ) { + if( m_config->showDurations() == ShowDurations::Always ) + stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + m_headerPrinted = false; + } + else { + if( m_config->showDurations() == ShowDurations::Always ) + stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + } + StreamingReporterBase::sectionEnded( _sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) { + StreamingReporterBase::testCaseEnded( _testCaseStats ); + m_headerPrinted = false; + } + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) { + if( currentGroupInfo.used ) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals( _testGroupStats.totals ); + stream << "\n" << std::endl; + } + StreamingReporterBase::testGroupEnded( _testGroupStats ); + } + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotalsDivider( _testRunStats.totals ); + printTotals( _testRunStats.totals ); + stream << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ), + stats( _stats ), + result( _stats.assertionResult ), + colour( Colour::None ), + message( result.getMessage() ), + messages( _stats.infoMessages ), + printInfoMessages( _printInfoMessages ) + { + switch( result.getResultType() ) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } + else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with message"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if( _stats.infoMessages.size() == 1 ) + messageLabel = "explicitly with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if( stats.totals.assertions.total() > 0 ) { + if( result.isOk() ) + stream << "\n"; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } + else { + stream << "\n"; + } + printMessage(); + } + + private: + void printResultType() const { + if( !passOrFail.empty() ) { + Colour colourGuard( colour ); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if( result.hasExpression() ) { + Colour colourGuard( Colour::OriginalExpression ); + stream << " "; + stream << result.getExpressionInMacro(); + stream << "\n"; + } + } + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + stream << "with expansion:\n"; + Colour colourGuard( Colour::ReconstructedExpression ); + stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; + } + } + void printMessage() const { + if( !messageLabel.empty() ) + stream << messageLabel << ":" << "\n"; + for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); + it != itEnd; + ++it ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || it->type != ResultWas::Info ) + stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; + } + } + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector messages; + bool printInfoMessages; + }; + + void lazyPrint() { + + if( !currentTestRunInfo.used ) + lazyPrintRunInfo(); + if( !currentGroupInfo.used ) + lazyPrintGroupInfo(); + + if( !m_headerPrinted ) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } + } + void lazyPrintRunInfo() { + stream << "\n" << getLineOfChars<'~'>() << "\n"; + Colour colour( Colour::SecondaryText ); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion << " host application.\n" + << "Run with -? for options\n\n"; + + if( m_config->rngSeed() != 0 ) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + currentTestRunInfo.used = true; + } + void lazyPrintGroupInfo() { + if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { + printClosedHeader( "Group: " + currentGroupInfo->name ); + currentGroupInfo.used = true; + } + } + void printTestCaseAndSectionHeader() { + assert( !m_sectionStack.empty() ); + printOpenHeader( currentTestCaseInfo->name ); + + if( m_sectionStack.size() > 1 ) { + Colour colourGuard( Colour::Headers ); + + std::vector::const_iterator + it = m_sectionStack.begin()+1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for( ; it != itEnd; ++it ) + printHeaderString( it->name, 2 ); + } + + SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; + + if( !lineInfo.empty() ){ + stream << getLineOfChars<'-'>() << "\n"; + Colour colourGuard( Colour::FileName ); + stream << lineInfo << "\n"; + } + stream << getLineOfChars<'.'>() << "\n" << std::endl; + } + + void printClosedHeader( std::string const& _name ) { + printOpenHeader( _name ); + stream << getLineOfChars<'.'>() << "\n"; + } + void printOpenHeader( std::string const& _name ) { + stream << getLineOfChars<'-'>() << "\n"; + { + Colour colourGuard( Colour::Headers ); + printHeaderString( _name ); + } + } + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { + std::size_t i = _string.find( ": " ); + if( i != std::string::npos ) + i+=2; + else + i = 0; + stream << Text( _string, TextAttributes() + .setIndent( indent+i) + .setInitialIndent( indent ) ) << "\n"; + } + + struct SummaryColumn { + + SummaryColumn( std::string const& _label, Colour::Code _colour ) + : label( _label ), + colour( _colour ) + {} + SummaryColumn addRow( std::size_t count ) { + std::ostringstream oss; + oss << count; + std::string row = oss.str(); + for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { + while( it->size() < row.size() ) + *it = " " + *it; + while( it->size() > row.size() ) + row = " " + row; + } + rows.push_back( row ); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector rows; + + }; + + void printTotals( Totals const& totals ) { + if( totals.testCases.total() == 0 ) { + stream << Colour( Colour::Warning ) << "No tests ran\n"; + } + else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { + stream << Colour( Colour::ResultSuccess ) << "All tests passed"; + stream << " (" + << pluralise( totals.assertions.passed, "assertion" ) << " in " + << pluralise( totals.testCases.passed, "test case" ) << ")" + << "\n"; + } + else { + + std::vector columns; + columns.push_back( SummaryColumn( "", Colour::None ) + .addRow( totals.testCases.total() ) + .addRow( totals.assertions.total() ) ); + columns.push_back( SummaryColumn( "passed", Colour::Success ) + .addRow( totals.testCases.passed ) + .addRow( totals.assertions.passed ) ); + columns.push_back( SummaryColumn( "failed", Colour::ResultError ) + .addRow( totals.testCases.failed ) + .addRow( totals.assertions.failed ) ); + columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) + .addRow( totals.testCases.failedButOk ) + .addRow( totals.assertions.failedButOk ) ); + + printSummaryRow( "test cases", columns, 0 ); + printSummaryRow( "assertions", columns, 1 ); + } + } + void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { + for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { + std::string value = it->rows[row]; + if( it->label.empty() ) { + stream << label << ": "; + if( value != "0" ) + stream << value; + else + stream << Colour( Colour::Warning ) << "- none -"; + } + else if( value != "0" ) { + stream << Colour( Colour::LightGrey ) << " | "; + stream << Colour( it->colour ) + << value << " " << it->label; + } + } + stream << "\n"; + } + + static std::size_t makeRatio( std::size_t number, std::size_t total ) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; + return ( ratio == 0 && number > 0 ) ? 1 : ratio; + } + static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { + if( i > j && i > k ) + return i; + else if( j > k ) + return j; + else + return k; + } + + void printTotalsDivider( Totals const& totals ) { + if( totals.testCases.total() > 0 ) { + std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); + std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); + std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); + while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )++; + while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )--; + + stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); + stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); + if( totals.testCases.allPassed() ) + stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); + else + stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); + } + else { + stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); + } + stream << "\n"; + } + void printSummaryDivider() { + stream << getLineOfChars<'-'>() << "\n"; + } + + private: + bool m_headerPrinted; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_compact.hpp +#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + CompactReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual ~CompactReporter(); + + static std::string getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( _testRunStats.totals ); + stream << "\n" << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ) + , stats( _stats ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( _printInfoMessages ) + {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch( result.getResultType() ) { + case ResultWas::Ok: + printResultType( Colour::ResultSuccess, passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) + printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); + else + printResultType( Colour::Error, failedString() ); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( Colour::Error, failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType( Colour::Error, failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType( Colour::Error, failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType( Colour::None, "info" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType( Colour::None, "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( Colour::Error, failedString() ); + printIssue( "explicitly" ); + printRemainingMessages( Colour::None ); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType( Colour::Error, "** internal error **" ); + break; + } + } + + private: + // Colour::LightGrey + + static Colour::Code dimColour() { return Colour::FileName; } + +#ifdef CATCH_PLATFORM_MAC + static const char* failedString() { return "FAILED"; } + static const char* passedString() { return "PASSED"; } +#else + static const char* failedString() { return "failed"; } + static const char* passedString() { return "passed"; } +#endif + + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ":"; + } + + void printResultType( Colour::Code colour, std::string passOrFail ) const { + if( !passOrFail.empty() ) { + { + Colour colourGuard( colour ); + stream << " " << passOrFail; + } + stream << ":"; + } + } + + void printIssue( std::string issue ) const { + stream << " " << issue; + } + + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ";"; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << " " << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << "'"; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if ( itMessage == messages.end() ) + return; + + // using messages.end() directly yields compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ":"; + } + + for(; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || itMessage->type != ResultWas::Info ) { + stream << " '" << itMessage->message << "'"; + if ( ++itMessage != itEnd ) { + Colour colourGuard( dimColour() ); + stream << " and"; + } + } + } + } + + private: + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; + }; + + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. + + std::string bothOrAll( std::size_t count ) const { + return count == 1 ? "" : count == 2 ? "both " : "all " ; + } + + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "No tests ran."; + } + else if( totals.testCases.failed == totals.testCases.total() ) { + Colour colour( Colour::ResultError ); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll( totals.assertions.failed ) : ""; + stream << + "Failed " << bothOrAll( totals.testCases.failed ) + << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << qualify_assertions_failed << + pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else if( totals.assertions.total() == 0 ) { + stream << + "Passed " << bothOrAll( totals.testCases.total() ) + << pluralise( totals.testCases.total(), "test case" ) + << " (no assertions)."; + } + else if( totals.assertions.failed ) { + Colour colour( Colour::ResultError ); + stream << + "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else { + Colour colour( Colour::ResultSuccess ); + stream << + "Passed " << bothOrAll( totals.testCases.passed ) + << pluralise( totals.testCases.passed, "test case" ) << + " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; + } + } + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch + +namespace Catch { + NonCopyable::~NonCopyable() {} + IShared::~IShared() {} + StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} + IContext::~IContext() {} + IResultCapture::~IResultCapture() {} + ITestCase::~ITestCase() {} + ITestCaseRegistry::~ITestCaseRegistry() {} + IRegistryHub::~IRegistryHub() {} + IMutableRegistryHub::~IMutableRegistryHub() {} + IExceptionTranslator::~IExceptionTranslator() {} + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} + IReporter::~IReporter() {} + IReporterFactory::~IReporterFactory() {} + IReporterRegistry::~IReporterRegistry() {} + IStreamingReporter::~IStreamingReporter() {} + AssertionStats::~AssertionStats() {} + SectionStats::~SectionStats() {} + TestCaseStats::~TestCaseStats() {} + TestGroupStats::~TestGroupStats() {} + TestRunStats::~TestRunStats() {} + CumulativeReporterBase::SectionNode::~SectionNode() {} + CumulativeReporterBase::~CumulativeReporterBase() {} + + StreamingReporterBase::~StreamingReporterBase() {} + ConsoleReporter::~ConsoleReporter() {} + CompactReporter::~CompactReporter() {} + IRunner::~IRunner() {} + IMutableContext::~IMutableContext() {} + IConfig::~IConfig() {} + XmlReporter::~XmlReporter() {} + JunitReporter::~JunitReporter() {} + TestRegistry::~TestRegistry() {} + FreeFunctionTestCase::~FreeFunctionTestCase() {} + IGeneratorInfo::~IGeneratorInfo() {} + IGeneratorsForTest::~IGeneratorsForTest() {} + TestSpec::Pattern::~Pattern() {} + TestSpec::NamePattern::~NamePattern() {} + TestSpec::TagPattern::~TagPattern() {} + TestSpec::ExcludedPattern::~ExcludedPattern() {} + + Matchers::Impl::StdString::Equals::~Equals() {} + Matchers::Impl::StdString::Contains::~Contains() {} + Matchers::Impl::StdString::StartsWith::~StartsWith() {} + Matchers::Impl::StdString::EndsWith::~EndsWith() {} + + void Config::dummy() {} +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#ifdef CATCH_CONFIG_MAIN +// #included from: internal/catch_default_main.hpp +#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED + +#ifndef __OBJC__ + +// Standard C/C++ main entry point +int main (int argc, char * const argv[]) { + return Catch::Session().run( argc, argv ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char* const*)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return result; +} + +#endif // __OBJC__ + +#endif + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +////// + +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) + +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) + +#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) +#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) +#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) +#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) +#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) + +#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) +#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) +#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) + #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) +#else + #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) + #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) +#endif +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) +#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) + +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) + +#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) +#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) +#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) +#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) +#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) + +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) + +#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) +#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) +#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) + #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) +#else +#define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) +#define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) +#define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) +#define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) +#define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) +#define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) +#endif +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) +#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define GIVEN( desc ) SECTION( " Given: " desc, "" ) +#define WHEN( desc ) SECTION( " When: " desc, "" ) +#define AND_WHEN( desc ) SECTION( "And when: " desc, "" ) +#define THEN( desc ) SECTION( " Then: " desc, "" ) +#define AND_THEN( desc ) SECTION( " And: " desc, "" ) + +using Catch::Detail::Approx; + +// #included from: internal/catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED \ No newline at end of file diff --git a/splinter/thirdparty/Eigen/Eigen/CMakeLists.txt b/splinter/thirdparty/Eigen/Eigen/CMakeLists.txt new file mode 100644 index 0000000000..9eb502b792 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/CMakeLists.txt @@ -0,0 +1,19 @@ +include(RegexUtils) +test_escape_string_as_regex() + +file(GLOB Eigen_directory_files "*") + +escape_string_as_regex(ESCAPED_CMAKE_CURRENT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + +foreach(f ${Eigen_directory_files}) + if(NOT f MATCHES "\\.txt" AND NOT f MATCHES "${ESCAPED_CMAKE_CURRENT_SOURCE_DIR}/[.].+" AND NOT f MATCHES "${ESCAPED_CMAKE_CURRENT_SOURCE_DIR}/src") + list(APPEND Eigen_directory_files_to_install ${f}) + endif() +endforeach(f ${Eigen_directory_files}) + +install(FILES + ${Eigen_directory_files_to_install} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen COMPONENT Devel + ) + +install(DIRECTORY src DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen COMPONENT Devel FILES_MATCHING PATTERN "*.h") diff --git a/splinter/Cholesky b/splinter/thirdparty/Eigen/Eigen/Cholesky similarity index 50% rename from splinter/Cholesky rename to splinter/thirdparty/Eigen/Eigen/Cholesky index f727f5d89c..1332b540d8 100644 --- a/splinter/Cholesky +++ b/splinter/thirdparty/Eigen/Eigen/Cholesky @@ -1,7 +1,15 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_CHOLESKY_MODULE_H #define EIGEN_CHOLESKY_MODULE_H #include "Core" +#include "Jacobi" #include "src/Core/util/DisableStupidWarnings.h" @@ -10,20 +18,26 @@ * * * This module provides two variants of the Cholesky decomposition for selfadjoint (hermitian) matrices. - * Those decompositions are accessible via the following MatrixBase methods: - * - MatrixBase::llt(), + * Those decompositions are also accessible via the following methods: + * - MatrixBase::llt() * - MatrixBase::ldlt() + * - SelfAdjointView::llt() + * - SelfAdjointView::ldlt() * * \code * #include * \endcode */ -#include "src/misc/Solve.h" #include "src/Cholesky/LLT.h" #include "src/Cholesky/LDLT.h" #ifdef EIGEN_USE_LAPACKE -#include "src/Cholesky/LLT_MKL.h" +#ifdef EIGEN_USE_MKL +#include "mkl_lapacke.h" +#else +#include "src/misc/lapacke.h" +#endif +#include "src/Cholesky/LLT_LAPACKE.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/splinter/thirdparty/Eigen/Eigen/CholmodSupport b/splinter/thirdparty/Eigen/Eigen/CholmodSupport new file mode 100644 index 0000000000..bed8924d31 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/CholmodSupport @@ -0,0 +1,48 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_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/CholmodSupport/CholmodSupport.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_CHOLMODSUPPORT_MODULE_H + diff --git a/splinter/Core b/splinter/thirdparty/Eigen/Eigen/Core similarity index 56% rename from splinter/Core rename to splinter/thirdparty/Eigen/Eigen/Core index 509c529e13..4d4901e030 100644 --- a/splinter/Core +++ b/splinter/thirdparty/Eigen/Eigen/Core @@ -14,6 +14,74 @@ // first thing Eigen does: stop the compiler from committing suicide #include "src/Core/util/DisableStupidWarnings.h" +#if defined(__CUDACC__) && !defined(EIGEN_NO_CUDA) + #define EIGEN_CUDACC __CUDACC__ +#endif + +#if defined(__CUDA_ARCH__) && !defined(EIGEN_NO_CUDA) + #define EIGEN_CUDA_ARCH __CUDA_ARCH__ +#endif + +#if defined(__CUDACC_VER_MAJOR__) && (__CUDACC_VER_MAJOR__ >= 9) +#define EIGEN_CUDACC_VER ((__CUDACC_VER_MAJOR__ * 10000) + (__CUDACC_VER_MINOR__ * 100)) +#elif defined(__CUDACC_VER__) +#define EIGEN_CUDACC_VER __CUDACC_VER__ +#else +#define EIGEN_CUDACC_VER 0 +#endif + +// Handle NVCC/CUDA/SYCL +#if defined(__CUDACC__) || defined(__SYCL_DEVICE_ONLY__) + // Do not try asserts on CUDA and SYCL! + #ifndef EIGEN_NO_DEBUG + #define EIGEN_NO_DEBUG + #endif + + #ifdef EIGEN_INTERNAL_DEBUGGING + #undef EIGEN_INTERNAL_DEBUGGING + #endif + + #ifdef EIGEN_EXCEPTIONS + #undef EIGEN_EXCEPTIONS + #endif + + // All functions callable from CUDA code must be qualified with __device__ + #ifdef __CUDACC__ + // Do not try to vectorize on CUDA and SYCL! + #ifndef EIGEN_DONT_VECTORIZE + #define EIGEN_DONT_VECTORIZE + #endif + + #define EIGEN_DEVICE_FUNC __host__ __device__ + // We need math_functions.hpp to ensure that that EIGEN_USING_STD_MATH macro + // works properly on the device side + #include + #else + #define EIGEN_DEVICE_FUNC + #endif + +#else + #define EIGEN_DEVICE_FUNC + +#endif + +// When compiling CUDA device code with NVCC, pull in math functions from the +// global namespace. In host mode, and when device doee with clang, use the +// std versions. +#if defined(__CUDA_ARCH__) && defined(__NVCC__) + #define EIGEN_USING_STD_MATH(FUNC) using ::FUNC; +#else + #define EIGEN_USING_STD_MATH(FUNC) using std::FUNC; +#endif + +#if (defined(_CPPUNWIND) || defined(__EXCEPTIONS)) && !defined(__CUDA_ARCH__) && !defined(EIGEN_EXCEPTIONS) && !defined(EIGEN_USE_SYCL) + #define EIGEN_EXCEPTIONS +#endif + +#ifdef EIGEN_EXCEPTIONS + #include +#endif + // then include this file where all our macros are defined. It's really important to do it first because // it's where we do all the alignment settings (platform detection and honoring the user's will if he // defined e.g. EIGEN_DONT_ALIGN) so it needs to be done before we do anything with vectorization. @@ -21,7 +89,7 @@ // Disable the ipa-cp-clone optimization flag with MinGW 6.x or newer (enabled by default with -O3) // See http://eigen.tuxfamily.org/bz/show_bug.cgi?id=556 for details. -#if defined(__MINGW32__) && EIGEN_GNUC_AT_LEAST(4,6) +#if EIGEN_COMP_MINGW && EIGEN_GNUC_AT_LEAST(4,6) #pragma GCC optimize ("-fno-ipa-cp-clone") #endif @@ -31,26 +99,26 @@ // 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 +// if alignment is disabled, then disable vectorization. Note: EIGEN_MAX_ALIGN_BYTES is the proper check, it takes into +// account both the user's will (EIGEN_MAX_ALIGN_BYTES,EIGEN_DONT_ALIGN) and our own platform checks +#if EIGEN_MAX_ALIGN_BYTES==0 #ifndef EIGEN_DONT_VECTORIZE #define EIGEN_DONT_VECTORIZE #endif #endif -#ifdef _MSC_VER +#if EIGEN_COMP_MSVC #include // for _aligned_malloc -- need it regardless of whether vectorization is enabled - #if (_MSC_VER >= 1500) // 2008 or later + #if (EIGEN_COMP_MSVC >= 1500) // 2008 or later // Remember that usage of defined() in a #define is undefined by the standard. // a user reported that in 64-bit mode, MSVC doesn't care to define _M_IX86_FP. - #if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || defined(_M_X64) + #if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || EIGEN_ARCH_x86_64 #define EIGEN_SSE2_ON_MSVC_2008_OR_LATER #endif #endif #else // Remember that usage of defined() in a #define is undefined by the standard - #if (defined __SSE2__) && ( (!defined __GNUC__) || (defined __INTEL_COMPILER) || EIGEN_GNUC_AT_LEAST(4,2) ) + #if (defined __SSE2__) && ( (!EIGEN_COMP_GNUC) || EIGEN_COMP_ICC || EIGEN_GNUC_AT_LEAST(4,2) ) #define EIGEN_SSE2_ON_NON_MSVC_BUT_NOT_OLD_GCC #endif #endif @@ -82,6 +150,31 @@ #ifdef __SSE4_2__ #define EIGEN_VECTORIZE_SSE4_2 #endif + #ifdef __AVX__ + #define EIGEN_VECTORIZE_AVX + #define EIGEN_VECTORIZE_SSE3 + #define EIGEN_VECTORIZE_SSSE3 + #define EIGEN_VECTORIZE_SSE4_1 + #define EIGEN_VECTORIZE_SSE4_2 + #endif + #ifdef __AVX2__ + #define EIGEN_VECTORIZE_AVX2 + #endif + #ifdef __FMA__ + #define EIGEN_VECTORIZE_FMA + #endif + #if defined(__AVX512F__) && defined(EIGEN_ENABLE_AVX512) + #define EIGEN_VECTORIZE_AVX512 + #define EIGEN_VECTORIZE_AVX2 + #define EIGEN_VECTORIZE_AVX + #define EIGEN_VECTORIZE_FMA + #ifdef __AVX512DQ__ + #define EIGEN_VECTORIZE_AVX512DQ + #endif + #ifdef __AVX512ER__ + #define EIGEN_VECTORIZE_AVX512ER + #endif + #endif // include files @@ -95,9 +188,10 @@ extern "C" { // In theory we should only include immintrin.h and not the other *mmintrin.h header files directly. // Doing so triggers some issues with ICC. However old gcc versions seems to not have this file, thus: - #if defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1110 + #if EIGEN_COMP_ICC >= 1110 #include #else + #include #include #include #ifdef EIGEN_VECTORIZE_SSE3 @@ -112,8 +206,20 @@ #ifdef EIGEN_VECTORIZE_SSE4_2 #include #endif + #if defined(EIGEN_VECTORIZE_AVX) || defined(EIGEN_VECTORIZE_AVX512) + #include + #endif #endif } // end extern "C" + #elif defined __VSX__ + #define EIGEN_VECTORIZE + #define EIGEN_VECTORIZE_VSX + #include + // We need to #undef all these ugly tokens defined in + // => use __vector instead of vector + #undef bool + #undef vector + #undef pixel #elif defined __ALTIVEC__ #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_ALTIVEC @@ -123,13 +229,35 @@ #undef bool #undef vector #undef pixel - #elif defined __ARM_NEON + #elif (defined __ARM_NEON) || (defined __ARM_NEON__) #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_NEON #include + #elif (defined __s390x__ && defined __VEC__) + #define EIGEN_VECTORIZE + #define EIGEN_VECTORIZE_ZVECTOR + #include #endif #endif +#if defined(__F16C__) && !defined(EIGEN_COMP_CLANG) + // We can use the optimized fp16 to float and float to fp16 conversion routines + #define EIGEN_HAS_FP16_C +#endif + +#if defined __CUDACC__ + #define EIGEN_VECTORIZE_CUDA + #include + #if EIGEN_CUDACC_VER >= 70500 + #define EIGEN_HAS_CUDA_FP16 + #endif +#endif + +#if defined EIGEN_HAS_CUDA_FP16 + #include + #include +#endif + #if (defined _OPENMP) && (!defined EIGEN_DONT_PARALLELIZE) #define EIGEN_HAS_OPENMP #endif @@ -139,7 +267,7 @@ #endif // MSVC for windows mobile does not have the errno.h file -#if !(defined(_MSC_VER) && defined(_WIN32_WCE)) && !defined(__ARMCC_VERSION) +#if !(EIGEN_COMP_MSVC && EIGEN_OS_WINCE) && !EIGEN_COMP_ARM #define EIGEN_HAS_ERRNO #endif @@ -159,29 +287,30 @@ // for min/max: #include +// for std::is_nothrow_move_assignable +#ifdef EIGEN_INCLUDE_TYPE_TRAITS +#include +#endif + // for outputting debug info #ifdef EIGEN_DEBUG_ASSIGN #include #endif // required for __cpuid, needs to be included after cmath -#if defined(_MSC_VER) && (defined(_M_IX86)||defined(_M_X64)) && (!defined(_WIN32_WCE)) +#if EIGEN_COMP_MSVC && EIGEN_ARCH_i386_OR_x86_64 && !EIGEN_OS_WINCE #include #endif -#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) - #define EIGEN_EXCEPTIONS -#endif - -#ifdef EIGEN_EXCEPTIONS - #include -#endif - /** \brief Namespace containing all symbols from the %Eigen library. */ namespace Eigen { inline static const char *SimdInstructionSetsInUse(void) { -#if defined(EIGEN_VECTORIZE_SSE4_2) +#if defined(EIGEN_VECTORIZE_AVX512) + return "AVX512, FMA, AVX2, AVX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2"; +#elif defined(EIGEN_VECTORIZE_AVX) + return "AVX SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2"; +#elif defined(EIGEN_VECTORIZE_SSE4_2) return "SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2"; #elif defined(EIGEN_VECTORIZE_SSE4_1) return "SSE, SSE2, SSE3, SSSE3, SSE4.1"; @@ -193,8 +322,12 @@ inline static const char *SimdInstructionSetsInUse(void) { return "SSE, SSE2"; #elif defined(EIGEN_VECTORIZE_ALTIVEC) return "AltiVec"; +#elif defined(EIGEN_VECTORIZE_VSX) + return "VSX"; #elif defined(EIGEN_VECTORIZE_NEON) return "ARM NEON"; +#elif defined(EIGEN_VECTORIZE_ZVECTOR) + return "S390X ZVECTOR"; #else return "None"; #endif @@ -202,42 +335,21 @@ inline static const char *SimdInstructionSetsInUse(void) { } // end namespace Eigen -#define STAGE10_FULL_EIGEN2_API 10 -#define STAGE20_RESOLVE_API_CONFLICTS 20 -#define STAGE30_FULL_EIGEN3_API 30 -#define STAGE40_FULL_EIGEN3_STRICTNESS 40 -#define STAGE99_NO_EIGEN2_SUPPORT 99 - -#if defined EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS - #define EIGEN2_SUPPORT - #define EIGEN2_SUPPORT_STAGE STAGE40_FULL_EIGEN3_STRICTNESS -#elif defined EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API - #define EIGEN2_SUPPORT - #define EIGEN2_SUPPORT_STAGE STAGE30_FULL_EIGEN3_API -#elif defined EIGEN2_SUPPORT_STAGE20_RESOLVE_API_CONFLICTS - #define EIGEN2_SUPPORT - #define EIGEN2_SUPPORT_STAGE STAGE20_RESOLVE_API_CONFLICTS -#elif defined EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API - #define EIGEN2_SUPPORT - #define EIGEN2_SUPPORT_STAGE STAGE10_FULL_EIGEN2_API -#elif defined EIGEN2_SUPPORT - // default to stage 3, that's what it's always meant - #define EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API - #define EIGEN2_SUPPORT_STAGE STAGE30_FULL_EIGEN3_API -#else - #define EIGEN2_SUPPORT_STAGE STAGE99_NO_EIGEN2_SUPPORT +#if defined EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS || defined EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API || defined EIGEN2_SUPPORT_STAGE20_RESOLVE_API_CONFLICTS || defined EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API || defined EIGEN2_SUPPORT +// This will generate an error message: +#error Eigen2-support is only available up to version 3.2. Please go to "http://eigen.tuxfamily.org/index.php?title=Eigen2" for further information #endif -#ifdef EIGEN2_SUPPORT -#undef minor -#endif +namespace Eigen { // we use size_t frequently and we'll never remember to prepend it with std:: everytime just to // ensure QNX/QCC support using std::size_t; -// gcc 4.6.0 wants std:: for ptrdiff_t +// gcc 4.6.0 wants std:: for ptrdiff_t using std::ptrdiff_t; +} + /** \defgroup Core_Module Core module * This is the main module of Eigen providing dense matrix and vector support * (both fixed and dynamic size) with all the features corresponding to a BLAS library @@ -249,8 +361,8 @@ using std::ptrdiff_t; */ #include "src/Core/util/Constants.h" -#include "src/Core/util/ForwardDeclarations.h" #include "src/Core/util/Meta.h" +#include "src/Core/util/ForwardDeclarations.h" #include "src/Core/util/StaticAssert.h" #include "src/Core/util/XprHelper.h" #include "src/Core/util/Memory.h" @@ -258,41 +370,94 @@ using std::ptrdiff_t; #include "src/Core/NumTraits.h" #include "src/Core/MathFunctions.h" #include "src/Core/GenericPacketMath.h" +#include "src/Core/MathFunctionsImpl.h" +#include "src/Core/arch/Default/ConjHelper.h" -#if defined EIGEN_VECTORIZE_SSE +#if defined EIGEN_VECTORIZE_AVX512 + #include "src/Core/arch/SSE/PacketMath.h" + #include "src/Core/arch/AVX/PacketMath.h" + #include "src/Core/arch/AVX512/PacketMath.h" + #include "src/Core/arch/AVX512/MathFunctions.h" +#elif defined EIGEN_VECTORIZE_AVX + // Use AVX for floats and doubles, SSE for integers + #include "src/Core/arch/SSE/PacketMath.h" + #include "src/Core/arch/SSE/Complex.h" + #include "src/Core/arch/SSE/MathFunctions.h" + #include "src/Core/arch/AVX/PacketMath.h" + #include "src/Core/arch/AVX/MathFunctions.h" + #include "src/Core/arch/AVX/Complex.h" + #include "src/Core/arch/AVX/TypeCasting.h" + #include "src/Core/arch/SSE/TypeCasting.h" +#elif defined EIGEN_VECTORIZE_SSE #include "src/Core/arch/SSE/PacketMath.h" #include "src/Core/arch/SSE/MathFunctions.h" #include "src/Core/arch/SSE/Complex.h" -#elif defined EIGEN_VECTORIZE_ALTIVEC + #include "src/Core/arch/SSE/TypeCasting.h" +#elif defined(EIGEN_VECTORIZE_ALTIVEC) || defined(EIGEN_VECTORIZE_VSX) #include "src/Core/arch/AltiVec/PacketMath.h" + #include "src/Core/arch/AltiVec/MathFunctions.h" #include "src/Core/arch/AltiVec/Complex.h" #elif defined EIGEN_VECTORIZE_NEON #include "src/Core/arch/NEON/PacketMath.h" + #include "src/Core/arch/NEON/MathFunctions.h" #include "src/Core/arch/NEON/Complex.h" +#elif defined EIGEN_VECTORIZE_ZVECTOR + #include "src/Core/arch/ZVector/PacketMath.h" + #include "src/Core/arch/ZVector/MathFunctions.h" + #include "src/Core/arch/ZVector/Complex.h" +#endif + +// Half float support +#include "src/Core/arch/CUDA/Half.h" +#include "src/Core/arch/CUDA/PacketMathHalf.h" +#include "src/Core/arch/CUDA/TypeCasting.h" + +#if defined EIGEN_VECTORIZE_CUDA + #include "src/Core/arch/CUDA/PacketMath.h" + #include "src/Core/arch/CUDA/MathFunctions.h" #endif #include "src/Core/arch/Default/Settings.h" -#include "src/Core/Functors.h" +#include "src/Core/functors/TernaryFunctors.h" +#include "src/Core/functors/BinaryFunctors.h" +#include "src/Core/functors/UnaryFunctors.h" +#include "src/Core/functors/NullaryFunctors.h" +#include "src/Core/functors/StlFunctors.h" +#include "src/Core/functors/AssignmentFunctors.h" + +// Specialized functors to enable the processing of complex numbers +// on CUDA devices +#include "src/Core/arch/CUDA/Complex.h" + +#include "src/Core/IO.h" #include "src/Core/DenseCoeffsBase.h" #include "src/Core/DenseBase.h" #include "src/Core/MatrixBase.h" #include "src/Core/EigenBase.h" +#include "src/Core/Product.h" +#include "src/Core/CoreEvaluators.h" +#include "src/Core/AssignEvaluator.h" + #ifndef EIGEN_PARSED_BY_DOXYGEN // work around Doxygen bug triggered by Assign.h r814874 // at least confirmed with Doxygen 1.5.5 and 1.5.6 #include "src/Core/Assign.h" #endif +#include "src/Core/ArrayBase.h" #include "src/Core/util/BlasUtil.h" #include "src/Core/DenseStorage.h" #include "src/Core/NestByValue.h" -#include "src/Core/ForceAlignedAccess.h" + +// #include "src/Core/ForceAlignedAccess.h" + #include "src/Core/ReturnByValue.h" #include "src/Core/NoAlias.h" #include "src/Core/PlainObjectBase.h" #include "src/Core/Matrix.h" #include "src/Core/Array.h" +#include "src/Core/CwiseTernaryOp.h" #include "src/Core/CwiseBinaryOp.h" #include "src/Core/CwiseUnaryOp.h" #include "src/Core/CwiseNullaryOp.h" @@ -300,32 +465,32 @@ using std::ptrdiff_t; #include "src/Core/SelfCwiseBinaryOp.h" #include "src/Core/Dot.h" #include "src/Core/StableNorm.h" -#include "src/Core/MapBase.h" #include "src/Core/Stride.h" +#include "src/Core/MapBase.h" #include "src/Core/Map.h" +#include "src/Core/Ref.h" #include "src/Core/Block.h" #include "src/Core/VectorBlock.h" -#include "src/Core/Ref.h" #include "src/Core/Transpose.h" #include "src/Core/DiagonalMatrix.h" #include "src/Core/Diagonal.h" #include "src/Core/DiagonalProduct.h" -#include "src/Core/PermutationMatrix.h" -#include "src/Core/Transpositions.h" #include "src/Core/Redux.h" #include "src/Core/Visitor.h" #include "src/Core/Fuzzy.h" -#include "src/Core/IO.h" #include "src/Core/Swap.h" #include "src/Core/CommaInitializer.h" -#include "src/Core/Flagged.h" -#include "src/Core/ProductBase.h" #include "src/Core/GeneralProduct.h" +#include "src/Core/Solve.h" +#include "src/Core/Inverse.h" +#include "src/Core/SolverBase.h" +#include "src/Core/PermutationMatrix.h" +#include "src/Core/Transpositions.h" #include "src/Core/TriangularMatrix.h" #include "src/Core/SelfAdjointView.h" #include "src/Core/products/GeneralBlockPanelKernel.h" #include "src/Core/products/Parallelizer.h" -#include "src/Core/products/CoeffBasedProduct.h" +#include "src/Core/ProductEvaluators.h" #include "src/Core/products/GeneralMatrixVector.h" #include "src/Core/products/GeneralMatrixMatrix.h" #include "src/Core/SolveTriangular.h" @@ -340,6 +505,7 @@ using std::ptrdiff_t; #include "src/Core/products/TriangularSolverVector.h" #include "src/Core/BandMatrix.h" #include "src/Core/CoreIterators.h" +#include "src/Core/ConditionEstimator.h" #include "src/Core/BooleanRedux.h" #include "src/Core/Select.h" @@ -347,18 +513,17 @@ using std::ptrdiff_t; #include "src/Core/Random.h" #include "src/Core/Replicate.h" #include "src/Core/Reverse.h" -#include "src/Core/ArrayBase.h" #include "src/Core/ArrayWrapper.h" #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" +#include "src/Core/products/GeneralMatrixMatrix_BLAS.h" +#include "src/Core/products/GeneralMatrixVector_BLAS.h" +#include "src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h" +#include "src/Core/products/SelfadjointMatrixMatrix_BLAS.h" +#include "src/Core/products/SelfadjointMatrixVector_BLAS.h" +#include "src/Core/products/TriangularMatrixMatrix_BLAS.h" +#include "src/Core/products/TriangularMatrixVector_BLAS.h" +#include "src/Core/products/TriangularSolverMatrix_BLAS.h" #endif // EIGEN_USE_BLAS #ifdef EIGEN_USE_MKL_VML @@ -369,8 +534,4 @@ using std::ptrdiff_t; #include "src/Core/util/ReenableStupidWarnings.h" -#ifdef EIGEN2_SUPPORT -#include "Eigen2Support" -#endif - #endif // EIGEN_CORE_H diff --git a/splinter/thirdparty/Eigen/Eigen/Dense b/splinter/thirdparty/Eigen/Eigen/Dense new file mode 100644 index 0000000000..5768910bd8 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/Dense @@ -0,0 +1,7 @@ +#include "Core" +#include "LU" +#include "Cholesky" +#include "QR" +#include "SVD" +#include "Geometry" +#include "Eigenvalues" diff --git a/splinter/thirdparty/Eigen/Eigen/Eigen b/splinter/thirdparty/Eigen/Eigen/Eigen new file mode 100644 index 0000000000..654c8dc638 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/Eigen @@ -0,0 +1,2 @@ +#include "Dense" +#include "Sparse" diff --git a/splinter/Eigenvalues b/splinter/thirdparty/Eigen/Eigen/Eigenvalues similarity index 68% rename from splinter/Eigenvalues rename to splinter/thirdparty/Eigen/Eigen/Eigenvalues index 53c5a73a27..f3f661b074 100644 --- a/splinter/Eigenvalues +++ b/splinter/thirdparty/Eigen/Eigen/Eigenvalues @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_EIGENVALUES_MODULE_H #define EIGEN_EIGENVALUES_MODULE_H @@ -25,6 +32,7 @@ * \endcode */ +#include "src/misc/RealSvd2x2.h" #include "src/Eigenvalues/Tridiagonalization.h" #include "src/Eigenvalues/RealSchur.h" #include "src/Eigenvalues/EigenSolver.h" @@ -37,9 +45,14 @@ #include "src/Eigenvalues/GeneralizedEigenSolver.h" #include "src/Eigenvalues/MatrixBaseEigenvalues.h" #ifdef EIGEN_USE_LAPACKE -#include "src/Eigenvalues/RealSchur_MKL.h" -#include "src/Eigenvalues/ComplexSchur_MKL.h" -#include "src/Eigenvalues/SelfAdjointEigenSolver_MKL.h" +#ifdef EIGEN_USE_MKL +#include "mkl_lapacke.h" +#else +#include "src/misc/lapacke.h" +#endif +#include "src/Eigenvalues/RealSchur_LAPACKE.h" +#include "src/Eigenvalues/ComplexSchur_LAPACKE.h" +#include "src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/splinter/thirdparty/Eigen/Eigen/Geometry b/splinter/thirdparty/Eigen/Eigen/Geometry new file mode 100644 index 0000000000..716d529529 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/Geometry @@ -0,0 +1,62 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_MODULE_H +#define EIGEN_GEOMETRY_MODULE_H + +#include "Core" + +#include "src/Core/util/DisableStupidWarnings.h" + +#include "SVD" +#include "LU" +#include + +/** \defgroup Geometry_Module Geometry module + * + * This module provides support for: + * - fixed-size homogeneous transformations + * - translation, scaling, 2D and 3D rotations + * - \link Quaternion quaternions \endlink + * - cross products (\ref MatrixBase::cross, \ref MatrixBase::cross3) + * - orthognal vector generation (\ref MatrixBase::unitOrthogonal) + * - some linear components: \link ParametrizedLine parametrized-lines \endlink and \link Hyperplane hyperplanes \endlink + * - \link AlignedBox axis aligned bounding boxes \endlink + * - \link umeyama least-square transformation fitting \endlink + * + * \code + * #include + * \endcode + */ + +#include "src/Geometry/OrthoMethods.h" +#include "src/Geometry/EulerAngles.h" + +#include "src/Geometry/Homogeneous.h" +#include "src/Geometry/RotationBase.h" +#include "src/Geometry/Rotation2D.h" +#include "src/Geometry/Quaternion.h" +#include "src/Geometry/AngleAxis.h" +#include "src/Geometry/Transform.h" +#include "src/Geometry/Translation.h" +#include "src/Geometry/Scaling.h" +#include "src/Geometry/Hyperplane.h" +#include "src/Geometry/ParametrizedLine.h" +#include "src/Geometry/AlignedBox.h" +#include "src/Geometry/Umeyama.h" + +// Use the SSE optimized version whenever possible. At the moment the +// SSE version doesn't compile when AVX is enabled +#if defined EIGEN_VECTORIZE_SSE && !defined EIGEN_VECTORIZE_AVX +#include "src/Geometry/arch/Geometry_SSE.h" +#endif + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_GEOMETRY_MODULE_H +/* vim: set filetype=cpp et sw=2 ts=2 ai: */ + diff --git a/splinter/Householder b/splinter/thirdparty/Eigen/Eigen/Householder similarity index 66% rename from splinter/Householder rename to splinter/thirdparty/Eigen/Eigen/Householder index 6e348db5c4..89cd81b1af 100644 --- a/splinter/Householder +++ b/splinter/thirdparty/Eigen/Eigen/Householder @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_MODULE_H #define EIGEN_HOUSEHOLDER_MODULE_H diff --git a/splinter/IterativeLinearSolvers b/splinter/thirdparty/Eigen/Eigen/IterativeLinearSolvers similarity index 63% rename from splinter/IterativeLinearSolvers rename to splinter/thirdparty/Eigen/Eigen/IterativeLinearSolvers index 0f4159dc19..957d5750b2 100644 --- a/splinter/IterativeLinearSolvers +++ b/splinter/thirdparty/Eigen/Eigen/IterativeLinearSolvers @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_ITERATIVELINEARSOLVERS_MODULE_H #define EIGEN_ITERATIVELINEARSOLVERS_MODULE_H @@ -12,28 +19,29 @@ * 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, + * - LeastSquaresConjugateGradient for rectangular least-square problems, * - 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 + * - DiagonalPreconditioner - also called Jacobi preconditioner, work very well on diagonal dominant matrices. + * - IncompleteLUT - 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 + \code + #include + \endcode */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - +#include "src/IterativeLinearSolvers/SolveWithGuess.h" #include "src/IterativeLinearSolvers/IterativeSolverBase.h" #include "src/IterativeLinearSolvers/BasicPreconditioners.h" #include "src/IterativeLinearSolvers/ConjugateGradient.h" +#include "src/IterativeLinearSolvers/LeastSquareConjugateGradient.h" #include "src/IterativeLinearSolvers/BiCGSTAB.h" #include "src/IterativeLinearSolvers/IncompleteLUT.h" +#include "src/IterativeLinearSolvers/IncompleteCholesky.h" #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/splinter/Jacobi b/splinter/thirdparty/Eigen/Eigen/Jacobi similarity index 68% rename from splinter/Jacobi rename to splinter/thirdparty/Eigen/Eigen/Jacobi index ba8a4dc36a..17c1d785a1 100644 --- a/splinter/Jacobi +++ b/splinter/thirdparty/Eigen/Eigen/Jacobi @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_MODULE_H #define EIGEN_JACOBI_MODULE_H diff --git a/splinter/LU b/splinter/thirdparty/Eigen/Eigen/LU similarity index 55% rename from splinter/LU rename to splinter/thirdparty/Eigen/Eigen/LU index db57955044..6418a86e19 100644 --- a/splinter/LU +++ b/splinter/thirdparty/Eigen/Eigen/LU @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_MODULE_H #define EIGEN_LU_MODULE_H @@ -16,25 +23,27 @@ * \endcode */ -#include "src/misc/Solve.h" #include "src/misc/Kernel.h" #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" +#ifdef EIGEN_USE_MKL +#include "mkl_lapacke.h" +#else +#include "src/misc/lapacke.h" +#endif +#include "src/LU/PartialPivLU_LAPACKE.h" #endif #include "src/LU/Determinant.h" -#include "src/LU/Inverse.h" +#include "src/LU/InverseImpl.h" -#if defined EIGEN_VECTORIZE_SSE +// Use the SSE optimized version whenever possible. At the moment the +// SSE version doesn't compile when AVX is enabled +#if defined EIGEN_VECTORIZE_SSE && !defined EIGEN_VECTORIZE_AVX #include "src/LU/arch/Inverse_SSE.h" #endif -#ifdef EIGEN2_SUPPORT - #include "src/Eigen2Support/LU.h" -#endif - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_LU_MODULE_H diff --git a/splinter/thirdparty/Eigen/Eigen/MetisSupport b/splinter/thirdparty/Eigen/Eigen/MetisSupport new file mode 100644 index 0000000000..85c41bf340 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/MetisSupport @@ -0,0 +1,35 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_METISSUPPORT_MODULE_H +#define EIGEN_METISSUPPORT_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +extern "C" { +#include +} + + +/** \ingroup Support_modules + * \defgroup MetisSupport_Module MetisSupport module + * + * \code + * #include + * \endcode + * This module defines an interface to the METIS reordering package (http://glaros.dtc.umn.edu/gkhome/views/metis). + * It can be used just as any other built-in method as explained in \link OrderingMethods_Module here. \endlink + */ + + +#include "src/MetisSupport/MetisSupport.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_METISSUPPORT_MODULE_H diff --git a/splinter/OrderingMethods b/splinter/thirdparty/Eigen/Eigen/OrderingMethods similarity index 88% rename from splinter/OrderingMethods rename to splinter/thirdparty/Eigen/Eigen/OrderingMethods index 7c0f1fffff..d8ea361936 100644 --- a/splinter/OrderingMethods +++ b/splinter/thirdparty/Eigen/Eigen/OrderingMethods @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_ORDERINGMETHODS_MODULE_H #define EIGEN_ORDERINGMETHODS_MODULE_H diff --git a/splinter/thirdparty/Eigen/Eigen/PaStiXSupport b/splinter/thirdparty/Eigen/Eigen/PaStiXSupport new file mode 100644 index 0000000000..de3a63b4d1 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/PaStiXSupport @@ -0,0 +1,48 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_MODULE_H +#define EIGEN_PASTIXSUPPORT_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +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/PaStiXSupport/PaStiXSupport.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_PASTIXSUPPORT_MODULE_H diff --git a/splinter/thirdparty/Eigen/Eigen/PardisoSupport b/splinter/thirdparty/Eigen/Eigen/PardisoSupport new file mode 100755 index 0000000000..340edf51fe --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/PardisoSupport @@ -0,0 +1,35 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_PARDISOSUPPORT_MODULE_H +#define EIGEN_PARDISOSUPPORT_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +#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/splinter/QR b/splinter/thirdparty/Eigen/Eigen/QR similarity index 51% rename from splinter/QR rename to splinter/thirdparty/Eigen/Eigen/QR index ac5b026935..c7e9144699 100644 --- a/splinter/QR +++ b/splinter/thirdparty/Eigen/Eigen/QR @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_MODULE_H #define EIGEN_QR_MODULE_H @@ -15,31 +22,30 @@ * * This module provides various QR decompositions * This module also provides some MatrixBase methods, including: - * - MatrixBase::qr(), + * - MatrixBase::householderQr() + * - MatrixBase::colPivHouseholderQr() + * - MatrixBase::fullPivHouseholderQr() * * \code * #include * \endcode */ -#include "src/misc/Solve.h" #include "src/QR/HouseholderQR.h" #include "src/QR/FullPivHouseholderQR.h" #include "src/QR/ColPivHouseholderQR.h" +#include "src/QR/CompleteOrthogonalDecomposition.h" #ifdef EIGEN_USE_LAPACKE -#include "src/QR/HouseholderQR_MKL.h" -#include "src/QR/ColPivHouseholderQR_MKL.h" +#ifdef EIGEN_USE_MKL +#include "mkl_lapacke.h" +#else +#include "src/misc/lapacke.h" #endif - -#ifdef EIGEN2_SUPPORT -#include "src/Eigen2Support/QR.h" +#include "src/QR/HouseholderQR_LAPACKE.h" +#include "src/QR/ColPivHouseholderQR_LAPACKE.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" -#ifdef EIGEN2_SUPPORT -#include "Eigenvalues" -#endif - #endif // EIGEN_QR_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ diff --git a/splinter/thirdparty/Eigen/Eigen/QtAlignedMalloc b/splinter/thirdparty/Eigen/Eigen/QtAlignedMalloc new file mode 100644 index 0000000000..4f07df02ae --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/QtAlignedMalloc @@ -0,0 +1,40 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_QTMALLOC_MODULE_H +#define EIGEN_QTMALLOC_MODULE_H + +#include "Core" + +#if (!EIGEN_MALLOC_ALREADY_ALIGNED) + +#include "src/Core/util/DisableStupidWarnings.h" + +void *qMalloc(std::size_t size) +{ + return Eigen::internal::aligned_malloc(size); +} + +void qFree(void *ptr) +{ + Eigen::internal::aligned_free(ptr); +} + +void *qRealloc(void *ptr, std::size_t size) +{ + void* newPtr = Eigen::internal::aligned_malloc(size); + std::memcpy(newPtr, ptr, size); + Eigen::internal::aligned_free(ptr); + return newPtr; +} + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif + +#endif // EIGEN_QTMALLOC_MODULE_H +/* vim: set filetype=cpp et sw=2 ts=2 ai: */ diff --git a/splinter/thirdparty/Eigen/Eigen/SPQRSupport b/splinter/thirdparty/Eigen/Eigen/SPQRSupport new file mode 100644 index 0000000000..f70390c176 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/SPQRSupport @@ -0,0 +1,34 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_SPQRSUPPORT_MODULE_H +#define EIGEN_SPQRSUPPORT_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +#include "SuiteSparseQR.hpp" + +/** \ingroup Support_modules + * \defgroup SPQRSupport_Module SuiteSparseQR module + * + * This module provides an interface to the SPQR library, which is part of the suitesparse package. + * + * \code + * #include + * \endcode + * + * In order to use this module, the SPQR headers must be accessible from the include paths, and your binary must be linked to the SPQR library and its dependencies (Cholmod, AMD, COLAMD,...). + * For a cmake based project, you can use our FindSPQR.cmake and FindCholmod.Cmake modules + * + */ + +#include "src/CholmodSupport/CholmodSupport.h" +#include "src/SPQRSupport/SuiteSparseQRSupport.h" + +#endif diff --git a/splinter/thirdparty/Eigen/Eigen/SVD b/splinter/thirdparty/Eigen/Eigen/SVD new file mode 100644 index 0000000000..5d0e75f7f7 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/SVD @@ -0,0 +1,51 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_SVD_MODULE_H +#define EIGEN_SVD_MODULE_H + +#include "QR" +#include "Householder" +#include "Jacobi" + +#include "src/Core/util/DisableStupidWarnings.h" + +/** \defgroup SVD_Module SVD module + * + * + * + * This module provides SVD decomposition for matrices (both real and complex). + * Two decomposition algorithms are provided: + * - JacobiSVD implementing two-sided Jacobi iterations is numerically very accurate, fast for small matrices, but very slow for larger ones. + * - BDCSVD implementing a recursive divide & conquer strategy on top of an upper-bidiagonalization which remains fast for large problems. + * These decompositions are accessible via the respective classes and following MatrixBase methods: + * - MatrixBase::jacobiSvd() + * - MatrixBase::bdcSvd() + * + * \code + * #include + * \endcode + */ + +#include "src/misc/RealSvd2x2.h" +#include "src/SVD/UpperBidiagonalization.h" +#include "src/SVD/SVDBase.h" +#include "src/SVD/JacobiSVD.h" +#include "src/SVD/BDCSVD.h" +#if defined(EIGEN_USE_LAPACKE) && !defined(EIGEN_USE_LAPACKE_STRICT) +#ifdef EIGEN_USE_MKL +#include "mkl_lapacke.h" +#else +#include "src/misc/lapacke.h" +#endif +#include "src/SVD/JacobiSVD_LAPACKE.h" +#endif + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_SVD_MODULE_H +/* vim: set filetype=cpp et sw=2 ts=2 ai: */ diff --git a/splinter/thirdparty/Eigen/Eigen/Sparse b/splinter/thirdparty/Eigen/Eigen/Sparse new file mode 100644 index 0000000000..136e681a1f --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/Sparse @@ -0,0 +1,36 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_MODULE_H +#define EIGEN_SPARSE_MODULE_H + +/** \defgroup Sparse_Module Sparse meta-module + * + * Meta-module including all related modules: + * - \ref SparseCore_Module + * - \ref OrderingMethods_Module + * - \ref SparseCholesky_Module + * - \ref SparseLU_Module + * - \ref SparseQR_Module + * - \ref IterativeLinearSolvers_Module + * + \code + #include + \endcode + */ + +#include "SparseCore" +#include "OrderingMethods" +#ifndef EIGEN_MPL2_ONLY +#include "SparseCholesky" +#endif +#include "SparseLU" +#include "SparseQR" +#include "IterativeLinearSolvers" + +#endif // EIGEN_SPARSE_MODULE_H + diff --git a/splinter/SparseCholesky b/splinter/thirdparty/Eigen/Eigen/SparseCholesky similarity index 95% rename from splinter/SparseCholesky rename to splinter/thirdparty/Eigen/Eigen/SparseCholesky index 9f5056aa1a..b6a320c402 100644 --- a/splinter/SparseCholesky +++ b/splinter/thirdparty/Eigen/Eigen/SparseCholesky @@ -34,8 +34,6 @@ #error The SparseCholesky module has nothing to offer in MPL2 only mode #endif -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" #include "src/SparseCholesky/SimplicialCholesky.h" #ifndef EIGEN_MPL2_ONLY diff --git a/splinter/SparseCore b/splinter/thirdparty/Eigen/Eigen/SparseCore similarity index 77% rename from splinter/SparseCore rename to splinter/thirdparty/Eigen/Eigen/SparseCore index 24bcf0156b..76966c4c4c 100644 --- a/splinter/SparseCore +++ b/splinter/thirdparty/Eigen/Eigen/SparseCore @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_SPARSECORE_MODULE_H #define EIGEN_SPARSECORE_MODULE_H @@ -26,37 +33,35 @@ * 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/SparseAssign.h" #include "src/SparseCore/CompressedStorage.h" #include "src/SparseCore/AmbiVector.h" +#include "src/SparseCore/SparseCompressedBase.h" #include "src/SparseCore/SparseMatrix.h" +#include "src/SparseCore/SparseMap.h" #include "src/SparseCore/MappedSparseMatrix.h" #include "src/SparseCore/SparseVector.h" -#include "src/SparseCore/SparseBlock.h" -#include "src/SparseCore/SparseTranspose.h" +#include "src/SparseCore/SparseRef.h" #include "src/SparseCore/SparseCwiseUnaryOp.h" #include "src/SparseCore/SparseCwiseBinaryOp.h" +#include "src/SparseCore/SparseTranspose.h" +#include "src/SparseCore/SparseBlock.h" #include "src/SparseCore/SparseDot.h" -#include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseRedux.h" -#include "src/SparseCore/SparseFuzzy.h" +#include "src/SparseCore/SparseView.h" +#include "src/SparseCore/SparseDiagonalProduct.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/SparseTriangularView.h" #include "src/SparseCore/TriangularSolver.h" -#include "src/SparseCore/SparseView.h" +#include "src/SparseCore/SparsePermutation.h" +#include "src/SparseCore/SparseFuzzy.h" +#include "src/SparseCore/SparseSolverBase.h" #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/splinter/SparseLU b/splinter/thirdparty/Eigen/Eigen/SparseLU similarity index 96% rename from splinter/SparseLU rename to splinter/thirdparty/Eigen/Eigen/SparseLU index 8527a49bd8..38b38b531d 100644 --- a/splinter/SparseLU +++ b/splinter/thirdparty/Eigen/Eigen/SparseLU @@ -20,9 +20,6 @@ * Please, see the documentation of the SparseLU class for more details. */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - // Ordering interface #include "OrderingMethods" diff --git a/splinter/SparseQR b/splinter/thirdparty/Eigen/Eigen/SparseQR similarity index 76% rename from splinter/SparseQR rename to splinter/thirdparty/Eigen/Eigen/SparseQR index 4ee42065ee..a6f3b7f7d7 100644 --- a/splinter/SparseQR +++ b/splinter/thirdparty/Eigen/Eigen/SparseQR @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_SPARSEQR_MODULE_H #define EIGEN_SPARSEQR_MODULE_H @@ -21,9 +28,6 @@ * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - #include "OrderingMethods" #include "src/SparseCore/SparseColEtree.h" #include "src/SparseQR/SparseQR.h" diff --git a/splinter/thirdparty/Eigen/Eigen/StdDeque b/splinter/thirdparty/Eigen/Eigen/StdDeque new file mode 100644 index 0000000000..bc68397be2 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/StdDeque @@ -0,0 +1,27 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009 Hauke Heibel +// +// 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 + +#include "Core" +#include + +#if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 && (EIGEN_MAX_STATIC_ALIGN_BYTES<=16) /* MSVC auto aligns up to 16 bytes in 64 bit builds */ + +#define EIGEN_DEFINE_STL_DEQUE_SPECIALIZATION(...) + +#else + +#include "src/StlSupport/StdDeque.h" + +#endif + +#endif // EIGEN_STDDEQUE_MODULE_H diff --git a/splinter/thirdparty/Eigen/Eigen/StdList b/splinter/thirdparty/Eigen/Eigen/StdList new file mode 100644 index 0000000000..4c6262c08c --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/StdList @@ -0,0 +1,26 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Hauke Heibel +// +// 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 + +#include "Core" +#include + +#if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 && (EIGEN_MAX_STATIC_ALIGN_BYTES<=16) /* MSVC auto aligns up to 16 bytes in 64 bit builds */ + +#define EIGEN_DEFINE_STL_LIST_SPECIALIZATION(...) + +#else + +#include "src/StlSupport/StdList.h" + +#endif + +#endif // EIGEN_STDLIST_MODULE_H diff --git a/splinter/thirdparty/Eigen/Eigen/StdVector b/splinter/thirdparty/Eigen/Eigen/StdVector new file mode 100644 index 0000000000..0c4697ad5b --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/StdVector @@ -0,0 +1,27 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009 Hauke Heibel +// +// 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 + +#include "Core" +#include + +#if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 && (EIGEN_MAX_STATIC_ALIGN_BYTES<=16) /* MSVC auto aligns up to 16 bytes in 64 bit builds */ + +#define EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(...) + +#else + +#include "src/StlSupport/StdVector.h" + +#endif + +#endif // EIGEN_STDVECTOR_MODULE_H diff --git a/splinter/thirdparty/Eigen/Eigen/SuperLUSupport b/splinter/thirdparty/Eigen/Eigen/SuperLUSupport new file mode 100644 index 0000000000..59312a82db --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/SuperLUSupport @@ -0,0 +1,64 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_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 This wrapper requires at least versions 4.0 of SuperLU. The 3.x versions are not supported. + * + * \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/SuperLUSupport/SuperLUSupport.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_SUPERLUSUPPORT_MODULE_H diff --git a/splinter/thirdparty/Eigen/Eigen/UmfPackSupport b/splinter/thirdparty/Eigen/Eigen/UmfPackSupport new file mode 100644 index 0000000000..00eec80875 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/UmfPackSupport @@ -0,0 +1,40 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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_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/UmfPackSupport/UmfPackSupport.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_UMFPACKSUPPORT_MODULE_H diff --git a/splinter/src/Cholesky/LDLT.h b/splinter/thirdparty/Eigen/Eigen/src/Cholesky/LDLT.h similarity index 70% rename from splinter/src/Cholesky/LDLT.h rename to splinter/thirdparty/Eigen/Eigen/src/Cholesky/LDLT.h index abd30bd916..0313a54bf3 100644 --- a/splinter/src/Cholesky/LDLT.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Cholesky/LDLT.h @@ -13,7 +13,7 @@ #ifndef EIGEN_LDLT_H #define EIGEN_LDLT_H -namespace Eigen { +namespace Eigen { namespace internal { template struct LDLT_Traits; @@ -28,8 +28,8 @@ namespace internal { * * \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. + * \tparam _MatrixType the type of the matrix of which to compute the LDL^T Cholesky decomposition + * \tparam _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 @@ -43,7 +43,9 @@ namespace internal { * 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. * - * \sa MatrixBase::ldlt(), class LLT + * This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism. + * + * \sa MatrixBase::ldlt(), SelfAdjointView::ldlt(), class LLT */ template class LDLT { @@ -52,15 +54,15 @@ template class LDLT enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, - Options = MatrixType::Options & ~RowMajorBit, // these are the options for the TmpMatrixType, we need a ColMajor matrix here! MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, UpLo = _UpLo }; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; - typedef typename MatrixType::Index Index; - typedef Matrix TmpMatrixType; + typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3 + typedef typename MatrixType::StorageIndex StorageIndex; + typedef Matrix TmpMatrixType; typedef Transpositions TranspositionType; typedef PermutationMatrix PermutationType; @@ -72,11 +74,11 @@ template class LDLT * The default constructor is useful in cases in which the user intends to * perform decompositions via LDLT::compute(const MatrixType&). */ - LDLT() - : m_matrix(), - m_transpositions(), + LDLT() + : m_matrix(), + m_transpositions(), m_sign(internal::ZeroSign), - m_isInitialized(false) + m_isInitialized(false) {} /** \brief Default Constructor with memory preallocation @@ -85,7 +87,7 @@ template class LDLT * according to the specified problem \a size. * \sa LDLT() */ - LDLT(Index size) + explicit LDLT(Index size) : m_matrix(size, size), m_transpositions(size), m_temporary(size), @@ -96,16 +98,35 @@ template class LDLT /** \brief Constructor with decomposition * * This calculates the decomposition for the input \a matrix. + * * \sa LDLT(Index size) */ - LDLT(const MatrixType& matrix) + template + explicit LDLT(const EigenBase& matrix) : m_matrix(matrix.rows(), matrix.cols()), m_transpositions(matrix.rows()), m_temporary(matrix.rows()), m_sign(internal::ZeroSign), m_isInitialized(false) { - compute(matrix); + compute(matrix.derived()); + } + + /** \brief Constructs a LDLT factorization from a given matrix + * + * This overloaded constructor is provided for \link InplaceDecomposition inplace decomposition \endlink when \c MatrixType is a Eigen::Ref. + * + * \sa LDLT(const EigenBase&) + */ + template + explicit LDLT(EigenBase& matrix) + : m_matrix(matrix.derived()), + m_transpositions(matrix.rows()), + m_temporary(matrix.rows()), + m_sign(internal::ZeroSign), + m_isInitialized(false) + { + compute(matrix.derived()); } /** Clear any existing decomposition @@ -151,13 +172,6 @@ template class LDLT eigen_assert(m_isInitialized && "LDLT is not initialized."); return m_sign == internal::PositiveSemiDef || m_sign == internal::ZeroSign; } - - #ifdef EIGEN2_SUPPORT - inline bool isPositiveDefinite() const - { - return isPositive(); - } - #endif /** \returns true if the matrix is negative (semidefinite) */ inline bool isNegative(void) const @@ -173,37 +187,38 @@ template class LDLT * \note_about_checking_solutions * * More precisely, this method solves \f$ A x = b \f$ using the decomposition \f$ A = P^T L D L^* P \f$ - * by solving the systems \f$ P^T y_1 = b \f$, \f$ L y_2 = y_1 \f$, \f$ D y_3 = y_2 \f$, + * by solving the systems \f$ P^T y_1 = b \f$, \f$ L y_2 = y_1 \f$, \f$ D y_3 = y_2 \f$, * \f$ L^* y_4 = y_3 \f$ and \f$ P x = y_4 \f$ in succession. If the matrix \f$ A \f$ is singular, then * \f$ D \f$ will also be singular (all the other matrices are invertible). In that case, the * least-square solution of \f$ D y_3 = y_2 \f$ is computed. This does not mean that this function * computes the least-square solution of \f$ A x = b \f$ is \f$ A \f$ is singular. * - * \sa MatrixBase::ldlt() + * \sa MatrixBase::ldlt(), SelfAdjointView::ldlt() */ template - inline const internal::solve_retval + inline const Solve solve(const MatrixBase& b) const { eigen_assert(m_isInitialized && "LDLT is not initialized."); eigen_assert(m_matrix.rows()==b.rows() && "LDLT::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); + return Solve(*this, b.derived()); } - #ifdef EIGEN2_SUPPORT - template - bool solve(const MatrixBase& b, ResultType *result) const - { - *result = this->solve(b); - return true; - } - #endif - template bool solveInPlace(MatrixBase &bAndX) const; - LDLT& compute(const MatrixType& matrix); + template + LDLT& compute(const EigenBase& matrix); + + /** \returns an estimate of the reciprocal condition number of the matrix of + * which \c *this is the LDLT decomposition. + */ + RealScalar rcond() const + { + eigen_assert(m_isInitialized && "LDLT is not initialized."); + return internal::rcond_estimate_helper(m_l1_norm, *this); + } template LDLT& rankUpdate(const MatrixBase& w, const RealScalar& alpha=1); @@ -220,22 +235,35 @@ template class LDLT MatrixType reconstructedMatrix() const; + /** \returns the adjoint of \c *this, that is, a const reference to the decomposition itself as the underlying matrix is self-adjoint. + * + * This method is provided for compatibility with other matrix decompositions, thus enabling generic code such as: + * \code x = decomposition.adjoint().solve(b) \endcode + */ + const LDLT& adjoint() const { return *this; }; + 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. + * \c NumericalIssue if the factorization failed because of a zero pivot. */ ComputationInfo info() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); - return Success; + return m_info; } + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + void _solve_impl(const RhsType &rhs, DstType &dst) const; + #endif + protected: - + static void check_template_parameters() { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); @@ -248,10 +276,12 @@ template class LDLT * is not stored), and the diagonal entries correspond to D. */ MatrixType m_matrix; + RealScalar m_l1_norm; TranspositionType m_transpositions; TmpMatrixType m_temporary; internal::SignMatrix m_sign; bool m_isInitialized; + ComputationInfo m_info; }; namespace internal { @@ -266,15 +296,17 @@ template<> struct ldlt_inplace using std::abs; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; + typedef typename TranspositionType::StorageIndex IndexType; eigen_assert(mat.rows()==mat.cols()); const Index size = mat.rows(); + bool found_zero_pivot = false; + bool ret = true; if (size <= 1) { transpositions.setIdentity(); - if (numext::real(mat.coeff(0,0)) > 0) sign = PositiveSemiDef; - else if (numext::real(mat.coeff(0,0)) < 0) sign = NegativeSemiDef; + if (numext::real(mat.coeff(0,0)) > static_cast(0) ) sign = PositiveSemiDef; + else if (numext::real(mat.coeff(0,0)) < static_cast(0)) sign = NegativeSemiDef; else sign = ZeroSign; return true; } @@ -286,7 +318,7 @@ template<> struct ldlt_inplace mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); index_of_biggest_in_corner += k; - transpositions.coeffRef(k) = index_of_biggest_in_corner; + transpositions.coeffRef(k) = IndexType(index_of_biggest_in_corner); if(k != index_of_biggest_in_corner) { // apply the transposition while taking care to consider only @@ -295,7 +327,7 @@ template<> struct ldlt_inplace mat.row(k).head(k).swap(mat.row(index_of_biggest_in_corner).head(k)); mat.col(k).tail(s).swap(mat.col(index_of_biggest_in_corner).tail(s)); std::swap(mat.coeffRef(k,k),mat.coeffRef(index_of_biggest_in_corner,index_of_biggest_in_corner)); - for(int i=k+1;i struct ldlt_inplace if(rs>0) A21.noalias() -= A20 * temp.head(k); } - + // In some previous versions of Eigen (e.g., 3.2.1), the scaling was omitted if the pivot - // was smaller than the cutoff value. However, soince LDLT is not rank-revealing - // we should only make sure we do not introduce INF or NaN values. - // LAPACK also uses 0 as the cutoff value. + // was smaller than the cutoff value. However, since LDLT is not rank-revealing + // we should only make sure that we do not introduce INF or NaN values. + // Remark that LAPACK also uses 0 as the cutoff value. RealScalar realAkk = numext::real(mat.coeffRef(k,k)); - if((rs>0) && (abs(realAkk) > RealScalar(0))) + bool pivot_is_valid = (abs(realAkk) > RealScalar(0)); + + if(k==0 && !pivot_is_valid) + { + // The entire diagonal is zero, there is nothing more to do + // except filling the transpositions, and checking whether the matrix is zero. + sign = ZeroSign; + for(Index j = 0; j0) && pivot_is_valid) A21 /= realAkk; + else if(rs>0) + ret = ret && (A21.array()==Scalar(0)).all(); + + if(found_zero_pivot && pivot_is_valid) ret = false; // factorization failed + else if(!pivot_is_valid) found_zero_pivot = true; if (sign == PositiveSemiDef) { - if (realAkk < 0) sign = Indefinite; + if (realAkk < static_cast(0)) sign = Indefinite; } else if (sign == NegativeSemiDef) { - if (realAkk > 0) sign = Indefinite; + if (realAkk > static_cast(0)) sign = Indefinite; } else if (sign == ZeroSign) { - if (realAkk > 0) sign = PositiveSemiDef; - else if (realAkk < 0) sign = NegativeSemiDef; + if (realAkk > static_cast(0)) sign = PositiveSemiDef; + else if (realAkk < static_cast(0)) sign = NegativeSemiDef; } } - return true; + return ret; } // Reference for the algorithm: Davis and Hager, "Multiple Rank @@ -356,7 +408,6 @@ template<> struct ldlt_inplace using numext::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); @@ -420,16 +471,16 @@ template struct LDLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m; } - static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } }; template struct LDLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m.adjoint(); } - static inline MatrixU getU(const MatrixType& m) { return m; } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); } }; } // end namespace internal @@ -437,21 +488,35 @@ template struct LDLT_Traits /** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix */ template -LDLT& LDLT::compute(const MatrixType& a) +template +LDLT& LDLT::compute(const EigenBase& a) { check_template_parameters(); - + eigen_assert(a.rows()==a.cols()); const Index size = a.rows(); - m_matrix = a; + m_matrix = a.derived(); + + // Compute matrix L1 norm = max abs column sum. + m_l1_norm = RealScalar(0); + // TODO move this code to SelfAdjointView + for (Index col = 0; col < size; ++col) { + RealScalar abs_col_sum; + if (_UpLo == Lower) + abs_col_sum = m_matrix.col(col).tail(size - col).template lpNorm<1>() + m_matrix.row(col).head(col).template lpNorm<1>(); + else + abs_col_sum = m_matrix.col(col).head(col).template lpNorm<1>() + m_matrix.row(col).tail(size - col).template lpNorm<1>(); + if (abs_col_sum > m_l1_norm) + m_l1_norm = abs_col_sum; + } m_transpositions.resize(size); m_isInitialized = false; m_temporary.resize(size); m_sign = internal::ZeroSign; - internal::ldlt_inplace::unblocked(m_matrix, m_transpositions, m_temporary, m_sign); + m_info = internal::ldlt_inplace::unblocked(m_matrix, m_transpositions, m_temporary, m_sign) ? Success : NumericalIssue; m_isInitialized = true; return *this; @@ -466,18 +531,19 @@ template template LDLT& LDLT::rankUpdate(const MatrixBase& w, const typename LDLT::RealScalar& sigma) { + typedef typename TranspositionType::StorageIndex IndexType; 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_transpositions.coeffRef(i) = IndexType(i); m_temporary.resize(size); m_sign = sigma>=0 ? internal::PositiveSemiDef : internal::NegativeSemiDef; m_isInitialized = true; @@ -488,53 +554,46 @@ LDLT& LDLT::rankUpdate(const MatrixBase -struct solve_retval, Rhs> - : solve_retval_base, Rhs> +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +template +void LDLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const { - typedef LDLT<_MatrixType,_UpLo> LDLTType; - EIGEN_MAKE_SOLVE_HELPERS(LDLTType,Rhs) - - template void evalTo(Dest& dst) const + eigen_assert(rhs.rows() == rows()); + // dst = P b + dst = m_transpositions * rhs; + + // dst = L^-1 (P b) + matrixL().solveInPlace(dst); + + // dst = D^-1 (L^-1 P b) + // more precisely, use pseudo-inverse of D (see bug 241) + using std::abs; + const typename Diagonal::RealReturnType vecD(vectorD()); + // In some previous versions, tolerance was set to the max of 1/highest (or rather numeric_limits::min()) + // and the maximal diagonal entry * epsilon as motivated by LAPACK's xGELSS: + // RealScalar tolerance = numext::maxi(vecD.array().abs().maxCoeff() * NumTraits::epsilon(),RealScalar(1) / NumTraits::highest()); + // However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the highest + // diagonal element is not well justified and leads to numerical issues in some cases. + // Moreover, Lapack's xSYTRS routines use 0 for the tolerance. + // Using numeric_limits::min() gives us more robustness to denormals. + RealScalar tolerance = (std::numeric_limits::min)(); + + for (Index i = 0; i < vecD.size(); ++i) { - eigen_assert(rhs().rows() == dec().matrixLDLT().rows()); - // dst = P b - dst = dec().transpositionsP() * rhs(); - - // dst = L^-1 (P b) - dec().matrixL().solveInPlace(dst); - - // dst = D^-1 (L^-1 P b) - // more precisely, use pseudo-inverse of D (see bug 241) - using std::abs; - using std::max; - typedef typename LDLTType::MatrixType MatrixType; - typedef typename LDLTType::RealScalar RealScalar; - const typename Diagonal::RealReturnType vectorD(dec().vectorD()); - // In some previous versions, tolerance was set to the max of 1/highest and the maximal diagonal entry * epsilon - // as motivated by LAPACK's xGELSS: - // RealScalar tolerance = (max)(vectorD.array().abs().maxCoeff() *NumTraits::epsilon(),RealScalar(1) / NumTraits::highest()); - // However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the highest - // diagonal element is not well justified and to numerical issues in some cases. - // Moreover, Lapack's xSYTRS routines use 0 for the tolerance. - RealScalar tolerance = RealScalar(1) / NumTraits::highest(); - - for (Index i = 0; i < vectorD.size(); ++i) { - if(abs(vectorD(i)) > tolerance) - dst.row(i) /= vectorD(i); - else - dst.row(i).setZero(); - } + if(abs(vecD(i)) > tolerance) + dst.row(i) /= vecD(i); + else + dst.row(i).setZero(); + } - // dst = L^-T (D^-1 L^-1 P b) - dec().matrixU().solveInPlace(dst); + // dst = L^-T (D^-1 L^-1 P b) + matrixU().solveInPlace(dst); - // dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b - dst = dec().transpositionsP().transpose() * dst; - } -}; + // dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b + dst = m_transpositions.transpose() * dst; } +#endif /** \internal use x = ldlt_object.solve(x); * @@ -588,6 +647,7 @@ MatrixType LDLT::reconstructedMatrix() const /** \cholesky_module * \returns the Cholesky decomposition with full pivoting without square root of \c *this + * \sa MatrixBase::ldlt() */ template inline const LDLT::PlainObject, UpLo> @@ -598,6 +658,7 @@ SelfAdjointView::ldlt() const /** \cholesky_module * \returns the Cholesky decomposition with full pivoting without square root of \c *this + * \sa SelfAdjointView::ldlt() */ template inline const LDLT::PlainObject> diff --git a/splinter/src/Cholesky/LLT.h b/splinter/thirdparty/Eigen/Eigen/src/Cholesky/LLT.h similarity index 70% rename from splinter/src/Cholesky/LLT.h rename to splinter/thirdparty/Eigen/Eigen/src/Cholesky/LLT.h index 7c11a2dc29..e1624d21b6 100644 --- a/splinter/src/Cholesky/LLT.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Cholesky/LLT.h @@ -10,7 +10,7 @@ #ifndef EIGEN_LLT_H #define EIGEN_LLT_H -namespace Eigen { +namespace Eigen { namespace internal{ template struct LLT_Traits; @@ -22,9 +22,9 @@ template struct LLT_Traits; * * \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. + * \tparam _MatrixType the type of the matrix of which we are computing the LL^T Cholesky decomposition + * \tparam _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. @@ -40,12 +40,18 @@ template struct LLT_Traits; * * 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) - * 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. + * + * \b Performance: for best performance, it is recommended to use a column-major storage format + * with the Lower triangular part (the default), or, equivalently, a row-major storage format + * with the Upper triangular part. Otherwise, you might get a 20% slowdown for the full factorization + * step, and rank-updates can be up to 3 times slower. + * + * This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism. + * + * Note that during the decomposition, only the lower (or upper, as defined by _UpLo) triangular part of A is considered. + * Therefore, the strict lower part does not have to store correct values. + * + * \sa MatrixBase::llt(), SelfAdjointView::llt(), class LDLT */ template class LLT { @@ -54,12 +60,12 @@ template class LLT enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, - Options = MatrixType::Options, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime }; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; - typedef typename MatrixType::Index Index; + typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3 + typedef typename MatrixType::StorageIndex StorageIndex; enum { PacketSize = internal::packet_traits::size, @@ -83,14 +89,30 @@ template class LLT * according to the specified problem \a size. * \sa LLT() */ - LLT(Index size) : m_matrix(size, size), + explicit LLT(Index size) : m_matrix(size, size), m_isInitialized(false) {} - LLT(const MatrixType& matrix) + template + explicit LLT(const EigenBase& matrix) : m_matrix(matrix.rows(), matrix.cols()), m_isInitialized(false) { - compute(matrix); + compute(matrix.derived()); + } + + /** \brief Constructs a LDLT factorization from a given matrix + * + * This overloaded constructor is provided for \link InplaceDecomposition inplace decomposition \endlink when + * \c MatrixType is a Eigen::Ref. + * + * \sa LLT(const EigenBase&) + */ + template + explicit LLT(EigenBase& matrix) + : m_matrix(matrix.derived()), + m_isInitialized(false) + { + compute(matrix.derived()); } /** \returns a view of the upper triangular matrix U */ @@ -115,33 +137,33 @@ template class LLT * Example: \include LLT_solve.cpp * Output: \verbinclude LLT_solve.out * - * \sa solveInPlace(), MatrixBase::llt() + * \sa solveInPlace(), MatrixBase::llt(), SelfAdjointView::llt() */ template - inline const internal::solve_retval + inline const Solve solve(const MatrixBase& b) const { eigen_assert(m_isInitialized && "LLT is not initialized."); eigen_assert(m_matrix.rows()==b.rows() && "LLT::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } - - #ifdef EIGEN2_SUPPORT - template - bool solve(const MatrixBase& b, ResultType *result) const - { - *result = this->solve(b); - return true; + return Solve(*this, b.derived()); } - - bool isPositiveDefinite() const { return true; } - #endif template - void solveInPlace(MatrixBase &bAndX) const; + void solveInPlace(const MatrixBase &bAndX) const; - LLT& compute(const MatrixType& matrix); + template + LLT& compute(const EigenBase& matrix); + + /** \returns an estimate of the reciprocal condition number of the matrix of + * which \c *this is the Cholesky decomposition. + */ + RealScalar rcond() const + { + eigen_assert(m_isInitialized && "LLT is not initialized."); + eigen_assert(m_info == Success && "LLT failed because matrix appears to be negative"); + return internal::rcond_estimate_helper(m_l1_norm, *this); + } /** \returns the LLT decomposition matrix * @@ -159,7 +181,7 @@ template class LLT /** \brief Reports whether previous computation was successful. * * \returns \c Success if computation was succesful, - * \c NumericalIssue if the matrix.appears to be negative. + * \c NumericalIssue if the matrix.appears not to be positive definite. */ ComputationInfo info() const { @@ -167,24 +189,38 @@ template class LLT return m_info; } + /** \returns the adjoint of \c *this, that is, a const reference to the decomposition itself as the underlying matrix is self-adjoint. + * + * This method is provided for compatibility with other matrix decompositions, thus enabling generic code such as: + * \code x = decomposition.adjoint().solve(b) \endcode + */ + const LLT& adjoint() const { return *this; }; + 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); + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + void _solve_impl(const RhsType &rhs, DstType &dst) const; + #endif + protected: - + static void check_template_parameters() { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); } - + /** \internal * Used to compute and store L * The strict upper part is not used and even not initialized. */ MatrixType m_matrix; + RealScalar m_l1_norm; bool m_isInitialized; ComputationInfo m_info; }; @@ -194,12 +230,11 @@ namespace internal { template struct llt_inplace; template -static typename MatrixType::Index llt_rank_update_lower(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) +static Index llt_rank_update_lower(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) { using std::sqrt; 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; @@ -268,11 +303,10 @@ template struct llt_inplace { typedef typename NumTraits::Real RealScalar; template - static typename MatrixType::Index unblocked(MatrixType& mat) + static Index unblocked(MatrixType& mat) { using std::sqrt; - typedef typename MatrixType::Index Index; - + eigen_assert(mat.rows()==mat.cols()); const Index size = mat.rows(); for(Index k = 0; k < size; ++k) @@ -295,9 +329,8 @@ template struct llt_inplace } template - static typename MatrixType::Index blocked(MatrixType& m) + static Index blocked(MatrixType& m) { - typedef typename MatrixType::Index Index; eigen_assert(m.rows()==m.cols()); Index size = m.rows(); if(size<32) @@ -322,36 +355,36 @@ template struct llt_inplace Index ret; if((ret=unblocked(A11))>=0) return k+ret; if(rs>0) A11.adjoint().template triangularView().template solveInPlace(A21); - if(rs>0) A22.template selfadjointView().rankUpdate(A21,-1); // bottleneck + if(rs>0) A22.template selfadjointView().rankUpdate(A21,typename NumTraits::Literal(-1)); // bottleneck } return -1; } template - static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) + static 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) + static EIGEN_STRONG_INLINE Index unblocked(MatrixType& mat) { Transpose matt(mat); return llt_inplace::unblocked(matt); } template - static EIGEN_STRONG_INLINE typename MatrixType::Index blocked(MatrixType& mat) + static EIGEN_STRONG_INLINE Index blocked(MatrixType& mat) { Transpose matt(mat); return llt_inplace::blocked(matt); } template - static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) + static Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) { Transpose matt(mat); return llt_inplace::rankUpdate(matt, vec.conjugate(), sigma); @@ -362,8 +395,8 @@ template struct LLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m; } - static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } static bool inplace_decomposition(MatrixType& m) { return llt_inplace::blocked(m)==-1; } }; @@ -372,8 +405,8 @@ template struct LLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m.adjoint(); } - static inline MatrixU getU(const MatrixType& m) { return m; } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); } static bool inplace_decomposition(MatrixType& m) { return llt_inplace::blocked(m)==-1; } }; @@ -388,14 +421,29 @@ template struct LLT_Traits * Output: \verbinclude TutorialLinAlgComputeTwice.out */ template -LLT& LLT::compute(const MatrixType& a) +template +LLT& LLT::compute(const EigenBase& a) { check_template_parameters(); - + eigen_assert(a.rows()==a.cols()); const Index size = a.rows(); m_matrix.resize(size, size); - m_matrix = a; + if (!internal::is_same_dense(m_matrix, a.derived())) + m_matrix = a.derived(); + + // Compute matrix L1 norm = max abs column sum. + m_l1_norm = RealScalar(0); + // TODO move this code to SelfAdjointView + for (Index col = 0; col < size; ++col) { + RealScalar abs_col_sum; + if (_UpLo == Lower) + abs_col_sum = m_matrix.col(col).tail(size - col).template lpNorm<1>() + m_matrix.row(col).head(col).template lpNorm<1>(); + else + abs_col_sum = m_matrix.col(col).head(col).template lpNorm<1>() + m_matrix.row(col).tail(size - col).template lpNorm<1>(); + if (abs_col_sum > m_l1_norm) + m_l1_norm = abs_col_sum; + } m_isInitialized = true; bool ok = Traits::inplace_decomposition(m_matrix); @@ -423,39 +471,33 @@ LLT<_MatrixType,_UpLo> LLT<_MatrixType,_UpLo>::rankUpdate(const VectorType& v, c return *this; } - -namespace internal { -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef LLT<_MatrixType,UpLo> LLTType; - EIGEN_MAKE_SOLVE_HELPERS(LLTType,Rhs) - template void evalTo(Dest& dst) const - { - dst = rhs(); - dec().solveInPlace(dst); - } -}; +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +template +void LLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const +{ + dst = rhs; + solveInPlace(dst); } +#endif /** \internal use x = llt_object.solve(x); - * + * * This is the \em in-place version of solve(). * * \param bAndX represents both the right-hand side matrix b and result x. * - * \returns true always! If you need to check for existence of solutions, use another decomposition like LU, QR, or SVD. + * This version avoids a copy when the right hand side matrix b is not needed anymore. * - * This version avoids a copy when the right hand side matrix b is not - * needed anymore. + * \warning The parameter is only marked 'const' to make the C++ compiler accept a temporary expression here. + * This function will const_cast it, so constness isn't honored here. * * \sa LLT::solve(), MatrixBase::llt() */ template template -void LLT::solveInPlace(MatrixBase &bAndX) const +void LLT::solveInPlace(const MatrixBase &bAndX) const { eigen_assert(m_isInitialized && "LLT is not initialized."); eigen_assert(m_matrix.rows()==bAndX.rows()); @@ -475,6 +517,7 @@ MatrixType LLT::reconstructedMatrix() const /** \cholesky_module * \returns the LLT decomposition of \c *this + * \sa SelfAdjointView::llt() */ template inline const LLT::PlainObject> @@ -485,6 +528,7 @@ MatrixBase::llt() const /** \cholesky_module * \returns the LLT decomposition of \c *this + * \sa SelfAdjointView::llt() */ template inline const LLT::PlainObject, UpLo> diff --git a/splinter/src/Cholesky/LLT_MKL.h b/splinter/thirdparty/Eigen/Eigen/src/Cholesky/LLT_LAPACKE.h similarity index 71% rename from splinter/src/Cholesky/LLT_MKL.h rename to splinter/thirdparty/Eigen/Eigen/src/Cholesky/LLT_LAPACKE.h index 66675d7476..bc6489e69a 100644 --- a/splinter/src/Cholesky/LLT_MKL.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Cholesky/LLT_LAPACKE.h @@ -25,41 +25,38 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************** - * Content : Eigen bindings to Intel(R) MKL + * Content : Eigen bindings to LAPACKe * 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 +#ifndef EIGEN_LLT_LAPACKE_H +#define EIGEN_LLT_LAPACKE_H namespace Eigen { namespace internal { -template struct mkl_llt; +template struct lapacke_llt; -#define EIGEN_MKL_LLT(EIGTYPE, MKLTYPE, MKLPREFIX) \ -template<> struct mkl_llt \ +#define EIGEN_LAPACKE_LLT(EIGTYPE, BLASTYPE, LAPACKE_PREFIX) \ +template<> struct lapacke_llt \ { \ template \ - static inline typename MatrixType::Index potrf(MatrixType& m, char uplo) \ + static inline 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(); \ + size = convert_index(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(); \ + lda = convert_index(m.outerStride()); \ \ - info = LAPACKE_##MKLPREFIX##potrf( matrix_order, uplo, size, (MKLTYPE*)a, lda ); \ + info = LAPACKE_##LAPACKE_PREFIX##potrf( matrix_order, uplo, size, (BLASTYPE*)a, lda ); \ info = (info==0) ? -1 : info>0 ? info-1 : size; \ return info; \ } \ @@ -67,36 +64,36 @@ template<> struct mkl_llt \ template<> struct llt_inplace \ { \ template \ - static typename MatrixType::Index blocked(MatrixType& m) \ + static Index blocked(MatrixType& m) \ { \ - return mkl_llt::potrf(m, 'L'); \ + return lapacke_llt::potrf(m, 'L'); \ } \ template \ - static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ + static 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) \ + static Index blocked(MatrixType& m) \ { \ - return mkl_llt::potrf(m, 'U'); \ + return lapacke_llt::potrf(m, 'U'); \ } \ template \ - static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ + static 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) +EIGEN_LAPACKE_LLT(double, double, d) +EIGEN_LAPACKE_LLT(float, float, s) +EIGEN_LAPACKE_LLT(dcomplex, lapack_complex_double, z) +EIGEN_LAPACKE_LLT(scomplex, lapack_complex_float, c) } // end namespace internal } // end namespace Eigen -#endif // EIGEN_LLT_MKL_H +#endif // EIGEN_LLT_LAPACKE_H diff --git a/splinter/src/CholmodSupport/CholmodSupport.h b/splinter/thirdparty/Eigen/Eigen/src/CholmodSupport/CholmodSupport.h similarity index 68% rename from splinter/src/CholmodSupport/CholmodSupport.h rename to splinter/thirdparty/Eigen/Eigen/src/CholmodSupport/CholmodSupport.h index 99dbe171c3..5719720238 100644 --- a/splinter/src/CholmodSupport/CholmodSupport.h +++ b/splinter/thirdparty/Eigen/Eigen/src/CholmodSupport/CholmodSupport.h @@ -14,46 +14,52 @@ 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) - { +template struct cholmod_configure_matrix; + +template<> struct cholmod_configure_matrix { + template + static void run(CholmodType& mat) { 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) - { +}; + +template<> struct cholmod_configure_matrix > { + template + static void run(CholmodType& mat) { mat.xtype = CHOLMOD_COMPLEX; mat.dtype = CHOLMOD_DOUBLE; } - else - { - eigen_assert(false && "Scalar type not supported by CHOLMOD"); - } -} +}; + +// Other scalar types are not yet suppotred by Cholmod +// template<> struct cholmod_configure_matrix { +// template +// static void run(CholmodType& mat) { +// mat.xtype = CHOLMOD_REAL; +// mat.dtype = CHOLMOD_SINGLE; +// } +// }; +// +// template<> struct cholmod_configure_matrix > { +// template +// static void run(CholmodType& mat) { +// mat.xtype = CHOLMOD_COMPLEX; +// mat.dtype = CHOLMOD_SINGLE; +// } +// }; } // 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) +template +cholmod_sparse viewAsCholmod(Ref > mat) { cholmod_sparse res; res.nzmax = mat.nonZeros(); - res.nrow = mat.rows();; + res.nrow = mat.rows(); res.ncol = mat.cols(); res.p = mat.outerIndexPtr(); res.i = mat.innerIndexPtr(); @@ -74,11 +80,11 @@ cholmod_sparse viewAsCholmod(SparseMatrix<_Scalar,_Options,_Index>& mat) res.dtype = 0; res.stype = -1; - if (internal::is_same<_Index,int>::value) + if (internal::is_same<_StorageIndex,int>::value) { res.itype = CHOLMOD_INT; } - else if (internal::is_same<_Index,SuiteSparse_long>::value) + else if (internal::is_same<_StorageIndex,long>::value) { res.itype = CHOLMOD_LONG; } @@ -88,7 +94,7 @@ cholmod_sparse viewAsCholmod(SparseMatrix<_Scalar,_Options,_Index>& mat) } // setup res.xtype - internal::cholmod_configure_matrix<_Scalar>(res); + internal::cholmod_configure_matrix<_Scalar>::run(res); res.stype = 0; @@ -98,16 +104,23 @@ cholmod_sparse viewAsCholmod(SparseMatrix<_Scalar,_Options,_Index>& mat) template const cholmod_sparse viewAsCholmod(const SparseMatrix<_Scalar,_Options,_Index>& mat) { - cholmod_sparse res = viewAsCholmod(mat.const_cast_derived()); + cholmod_sparse res = viewAsCholmod(Ref >(mat.const_cast_derived())); + return res; +} + +template +const cholmod_sparse viewAsCholmod(const SparseVector<_Scalar,_Options,_Index>& mat) +{ + cholmod_sparse res = viewAsCholmod(Ref >(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 viewAsCholmod(const SparseSelfAdjointView, UpLo>& mat) { - cholmod_sparse res = viewAsCholmod(mat.matrix().const_cast_derived()); + cholmod_sparse res = viewAsCholmod(Ref >(mat.matrix().const_cast_derived())); if(UpLo==Upper) res.stype = 1; if(UpLo==Lower) res.stype = -1; @@ -131,19 +144,19 @@ cholmod_dense viewAsCholmod(MatrixBase& mat) res.x = (void*)(mat.derived().data()); res.z = 0; - internal::cholmod_configure_matrix(res); + internal::cholmod_configure_matrix::run(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) +template +MappedSparseMatrix viewAsEigen(cholmod_sparse& cm) { - return MappedSparseMatrix - (cm.nrow, cm.ncol, static_cast(cm.p)[cm.ncol], - static_cast(cm.p), static_cast(cm.i),static_cast(cm.x) ); + return MappedSparseMatrix + (cm.nrow, cm.ncol, static_cast(cm.p)[cm.ncol], + static_cast(cm.p), static_cast(cm.i),static_cast(cm.x) ); } enum CholmodMode { @@ -157,29 +170,39 @@ enum CholmodMode { * \sa class CholmodSupernodalLLT, class CholmodSimplicialLDLT, class CholmodSimplicialLLT */ template -class CholmodBase : internal::noncopyable +class CholmodBase : public SparseSolverBase { + protected: + typedef SparseSolverBase Base; + using Base::derived; + using Base::m_isInitialized; 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; + typedef typename MatrixType::StorageIndex StorageIndex; + enum { + ColsAtCompileTime = MatrixType::ColsAtCompileTime, + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime + }; public: CholmodBase() - : m_cholmodFactor(0), m_info(Success), m_isInitialized(false) + : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false) { - m_shiftOffset[0] = m_shiftOffset[1] = RealScalar(0.0); + EIGEN_STATIC_ASSERT((internal::is_same::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY); + m_shiftOffset[0] = m_shiftOffset[1] = 0.0; cholmod_start(&m_cholmod); } - CholmodBase(const MatrixType& matrix) - : m_cholmodFactor(0), m_info(Success), m_isInitialized(false) + explicit CholmodBase(const MatrixType& matrix) + : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false) { - m_shiftOffset[0] = m_shiftOffset[1] = RealScalar(0.0); + EIGEN_STATIC_ASSERT((internal::is_same::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY); + m_shiftOffset[0] = m_shiftOffset[1] = 0.0; cholmod_start(&m_cholmod); compute(matrix); } @@ -191,11 +214,8 @@ class CholmodBase : internal::noncopyable 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); } + inline StorageIndex cols() const { return internal::convert_index(m_cholmodFactor->n); } + inline StorageIndex rows() const { return internal::convert_index(m_cholmodFactor->n); } /** \brief Reports whether previous computation was successful. * @@ -216,34 +236,6 @@ class CholmodBase : internal::noncopyable 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 sparsity pattern of \a matrix. * * This function is particularly useful when solving for several problems having the same structure. @@ -277,7 +269,7 @@ class CholmodBase : internal::noncopyable eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView()); cholmod_factorize_p(&A, m_shiftOffset, 0, 0, m_cholmodFactor, &m_cholmod); - + // If the factorization failed, minor is the column at which it did. On success minor == n. this->m_info = (m_cholmodFactor->minor == m_cholmodFactor->n ? Success : NumericalIssue); m_factorizationIsOk = true; @@ -290,20 +282,22 @@ class CholmodBase : internal::noncopyable #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal */ template - void _solve(const MatrixBase &b, MatrixBase &dest) const + void _solve_impl(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_UNUSED_VARIABLE(size); eigen_assert(size==b.rows()); + + // Cholmod needs column-major stoarge without inner-stride, which corresponds to the default behavior of Ref. + Ref > b_ref(b.derived()); - // note: cd stands for Cholmod Dense - Rhs& b_ref(b.const_cast_derived()); cholmod_dense b_cd = viewAsCholmod(b_ref); cholmod_dense* x_cd = cholmod_solve(CHOLMOD_A, m_cholmodFactor, &b_cd, &m_cholmod); if(!x_cd) { this->m_info = NumericalIssue; + return; } // TODO optimize this copy by swapping when possible (be careful with alignment, etc.) dest = Matrix::Map(reinterpret_cast(x_cd->x),b.rows(),b.cols()); @@ -311,8 +305,8 @@ class CholmodBase : internal::noncopyable } /** \internal */ - template - void _solve(const SparseMatrix &b, SparseMatrix &dest) const + template + void _solve_impl(const SparseMatrixBase &b, SparseMatrixBase &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; @@ -320,14 +314,16 @@ class CholmodBase : internal::noncopyable eigen_assert(size==b.rows()); // note: cs stands for Cholmod Sparse - cholmod_sparse b_cs = viewAsCholmod(b); + Ref > b_ref(b.const_cast_derived()); + cholmod_sparse b_cs = viewAsCholmod(b_ref); cholmod_sparse* x_cs = cholmod_spsolve(CHOLMOD_A, m_cholmodFactor, &b_cs, &m_cholmod); if(!x_cs) { this->m_info = NumericalIssue; + return; } // TODO optimize this copy by swapping when possible (be careful with alignment, etc.) - dest = viewAsEigen(*x_cs); + dest.derived() = viewAsEigen(*x_cs); cholmod_free_sparse(&x_cs, &m_cholmod); } #endif // EIGEN_PARSED_BY_DOXYGEN @@ -344,10 +340,61 @@ class CholmodBase : internal::noncopyable */ Derived& setShift(const RealScalar& offset) { - m_shiftOffset[0] = offset; + m_shiftOffset[0] = double(offset); return derived(); } + /** \returns the determinant of the underlying matrix from the current factorization */ + Scalar determinant() const + { + using std::exp; + return exp(logDeterminant()); + } + + /** \returns the log determinant of the underlying matrix from the current factorization */ + Scalar logDeterminant() const + { + using std::log; + using numext::real; + eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); + + RealScalar logDet = 0; + Scalar *x = static_cast(m_cholmodFactor->x); + if (m_cholmodFactor->is_super) + { + // Supernodal factorization stored as a packed list of dense column-major blocs, + // as described by the following structure: + + // super[k] == index of the first column of the j-th super node + StorageIndex *super = static_cast(m_cholmodFactor->super); + // pi[k] == offset to the description of row indices + StorageIndex *pi = static_cast(m_cholmodFactor->pi); + // px[k] == offset to the respective dense block + StorageIndex *px = static_cast(m_cholmodFactor->px); + + Index nb_super_nodes = m_cholmodFactor->nsuper; + for (Index k=0; k < nb_super_nodes; ++k) + { + StorageIndex ncols = super[k + 1] - super[k]; + StorageIndex nrows = pi[k + 1] - pi[k]; + + Map, 0, InnerStride<> > sk(x + px[k], ncols, InnerStride<>(nrows+1)); + logDet += sk.real().log().sum(); + } + } + else + { + // Simplicial factorization stored as standard CSC matrix. + StorageIndex *p = static_cast(m_cholmodFactor->p); + Index size = m_cholmodFactor->n; + for (Index k=0; kis_ll) + logDet *= 2.0; + return logDet; + }; + template void dumpMemory(Stream& /*s*/) {} @@ -355,9 +402,8 @@ class CholmodBase : internal::noncopyable protected: mutable cholmod_common m_cholmod; cholmod_factor* m_cholmodFactor; - RealScalar m_shiftOffset[2]; + double m_shiftOffset[2]; mutable ComputationInfo m_info; - bool m_isInitialized; int m_factorizationIsOk; int m_analysisIsOk; }; @@ -376,9 +422,13 @@ class CholmodBase : internal::noncopyable * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. * + * \implsparsesolverconcept + * * 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 + * \warning Only double precision real and complex scalar types are supported by Cholmod. + * + * \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLLT */ template class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT<_MatrixType, _UpLo> > @@ -395,7 +445,7 @@ class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimpl CholmodSimplicialLLT(const MatrixType& matrix) : Base() { init(); - Base::compute(matrix); + this->compute(matrix); } ~CholmodSimplicialLLT() {} @@ -423,9 +473,13 @@ class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimpl * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. * + * \implsparsesolverconcept + * * 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 + * \warning Only double precision real and complex scalar types are supported by Cholmod. + * + * \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLDLT */ template class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT<_MatrixType, _UpLo> > @@ -442,7 +496,7 @@ class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimp CholmodSimplicialLDLT(const MatrixType& matrix) : Base() { init(); - Base::compute(matrix); + this->compute(matrix); } ~CholmodSimplicialLDLT() {} @@ -468,9 +522,13 @@ class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimp * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. * + * \implsparsesolverconcept + * * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. * - * \sa \ref TutorialSparseDirectSolvers + * \warning Only double precision real and complex scalar types are supported by Cholmod. + * + * \sa \ref TutorialSparseSolverConcept */ template class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT<_MatrixType, _UpLo> > @@ -487,7 +545,7 @@ class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSuper CholmodSupernodalLLT(const MatrixType& matrix) : Base() { init(); - Base::compute(matrix); + this->compute(matrix); } ~CholmodSupernodalLLT() {} @@ -515,9 +573,13 @@ class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSuper * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. * + * \implsparsesolverconcept + * * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. * - * \sa \ref TutorialSparseDirectSolvers + * \warning Only double precision real and complex scalar types are supported by Cholmod. + * + * \sa \ref TutorialSparseSolverConcept */ template class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecomposition<_MatrixType, _UpLo> > @@ -534,7 +596,7 @@ class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecom CholmodDecomposition(const MatrixType& matrix) : Base() { init(); - Base::compute(matrix); + this->compute(matrix); } ~CholmodDecomposition() {} @@ -572,36 +634,6 @@ class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecom } }; -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/splinter/src/Core/Array.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Array.h similarity index 79% rename from splinter/src/Core/Array.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/Array.h index 0b9c38c821..e10020d4fd 100644 --- a/splinter/src/Core/Array.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Array.h @@ -12,7 +12,16 @@ namespace Eigen { -/** \class Array +namespace internal { +template +struct traits > : traits > +{ + typedef ArrayXpr XprKind; + typedef ArrayBase > XprBase; +}; +} + +/** \class Array * \ingroup Core_Module * * \brief General-purpose arrays with easy API for coefficient-wise operations @@ -24,20 +33,14 @@ namespace Eigen { * API for the %Matrix class provides easy access to linear-algebra * operations. * + * See documentation of class Matrix for detailed information on the template parameters + * storage layout. + * * 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_ARRAY_PLUGIN. + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_ARRAY_PLUGIN. * - * \sa \ref TutorialArrayClass, \ref TopicClassHierarchy + * \sa \blank \ref TutorialArrayClass, \ref TopicClassHierarchy */ -namespace internal { -template -struct traits > : traits > -{ - typedef ArrayXpr XprKind; - typedef ArrayBase > XprBase; -}; -} - template class Array : public PlainObjectBase > @@ -69,11 +72,27 @@ class Array * the usage of 'using'. This should be done only for operator=. */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array& operator=(const EigenBase &other) { return Base::operator=(other); } + /** Set all the entries to \a value. + * \sa DenseBase::setConstant(), DenseBase::fill() + */ + /* This overload is needed because the usage of + * using Base::operator=; + * fails on MSVC. Since the code below is working with GCC and MSVC, we skipped + * the usage of 'using'. This should be done only for operator=. + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array& operator=(const Scalar &value) + { + Base::setConstant(value); + return *this; + } + /** Copies the value of the expression \a other into \c *this with automatic resizing. * * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), @@ -84,7 +103,8 @@ class Array * remain row-vectors and vectors remain vectors. */ template - EIGEN_STRONG_INLINE Array& operator=(const ArrayBase& other) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array& operator=(const DenseBase& other) { return Base::_set(other); } @@ -92,11 +112,12 @@ class Array /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array& operator=(const Array& other) { return Base::_set(other); } - + /** Default constructor. * * For fixed-size matrices, does nothing. @@ -107,6 +128,7 @@ class Array * * \sa resize(Index,Index) */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array() : Base() { Base::_check_template_params(); @@ -116,6 +138,7 @@ class Array #ifndef EIGEN_PARSED_BY_DOXYGEN // FIXME is it still needed ?? /** \internal */ + EIGEN_DEVICE_FUNC Array(internal::constructor_without_unaligned_array_assert) : Base(internal::constructor_without_unaligned_array_assert()) { @@ -124,56 +147,64 @@ class Array } #endif -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - Array(Array&& other) +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + Array(Array&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_constructible::value) : Base(std::move(other)) { Base::_check_template_params(); if (RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic) Base::_set_noalias(other); } - Array& operator=(Array&& other) + EIGEN_DEVICE_FUNC + Array& operator=(Array&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_assignable::value) { other.swap(*this); return *this; } #endif - /** Constructs a vector or row-vector with given dimension. \only_for_vectors - * - * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, - * it is redundant to pass the dimension here, so it makes more sense to use the default - * constructor Matrix() instead. - */ - EIGEN_STRONG_INLINE explicit Array(Index dim) - : Base(dim, RowsAtCompileTime == 1 ? 1 : dim, ColsAtCompileTime == 1 ? 1 : dim) + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE explicit Array(const T& x) { Base::_check_template_params(); - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Array) - eigen_assert(dim >= 0); - eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == dim); - EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + Base::template _init1(x); } - #ifndef EIGEN_PARSED_BY_DOXYGEN template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const T0& val0, const T1& val1) { Base::_check_template_params(); this->template _init2(val0, val1); } #else - /** constructs an uninitialized matrix with \a rows rows and \a cols columns. + /** \brief Constructs a fixed-sized array initialized with coefficients starting at \a data */ + EIGEN_DEVICE_FUNC explicit Array(const Scalar *data); + /** Constructs a vector or row-vector with given dimension. \only_for_vectors + * + * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, + * it is redundant to pass the dimension here, so it makes more sense to use the default + * constructor Array() instead. + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE explicit Array(Index dim); + /** constructs an initialized 1x1 Array with the given coefficient */ + Array(const Scalar& value); + /** constructs an uninitialized array with \a rows rows and \a cols columns. * - * This is useful for dynamic-size matrices. For fixed-size matrices, + * This is useful for dynamic-size arrays. For fixed-size arrays, * it is redundant to pass these parameters, so one should use the default constructor - * Matrix() instead. */ + * Array() instead. */ Array(Index rows, Index cols); /** constructs an initialized 2D vector with given coefficients */ Array(const Scalar& val0, const Scalar& val1); #endif /** constructs an initialized 3D vector with given coefficients */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2) { Base::_check_template_params(); @@ -183,6 +214,7 @@ class Array m_storage.data()[2] = val2; } /** constructs an initialized 4D vector with given coefficients */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2, const Scalar& val3) { Base::_check_template_params(); @@ -193,51 +225,27 @@ class Array m_storage.data()[3] = val3; } - explicit Array(const Scalar *data); - - /** Constructor copying the value of the expression \a other */ - template - EIGEN_STRONG_INLINE Array(const ArrayBase& other) - : Base(other.rows() * other.cols(), other.rows(), other.cols()) - { - Base::_check_template_params(); - Base::_set_noalias(other); - } /** Copy constructor */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const Array& other) - : Base(other.rows() * other.cols(), other.rows(), other.cols()) - { - Base::_check_template_params(); - Base::_set_noalias(other); - } - /** Copy constructor with in-place evaluation */ - template - EIGEN_STRONG_INLINE Array(const ReturnByValue& other) - { - Base::_check_template_params(); - Base::resize(other.rows(), other.cols()); - other.evalTo(*this); - } + : Base(other) + { } - /** \sa MatrixBase::operator=(const EigenBase&) */ - template - EIGEN_STRONG_INLINE Array(const EigenBase &other) - : Base(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) - { - Base::_check_template_params(); - Base::_resize_to_match(other); - *this = other; - } + private: + struct PrivateType {}; + public: - /** Override MatrixBase::swap() since for dynamic-sized matrices of same type it is enough to swap the - * data pointers. - */ + /** \sa MatrixBase::operator=(const EigenBase&) */ template - void swap(ArrayBase const & other) - { this->_swap(other.derived()); } - - inline Index innerStride() const { return 1; } - inline Index outerStride() const { return this->innerSize(); } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array(const EigenBase &other, + typename internal::enable_if::value, + PrivateType>::type = PrivateType()) + : Base(other.derived()) + { } + + EIGEN_DEVICE_FUNC inline Index innerStride() const { return 1; } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return this->innerSize(); } #ifdef EIGEN_ARRAY_PLUGIN #include EIGEN_ARRAY_PLUGIN diff --git a/splinter/src/Core/ArrayBase.h b/splinter/thirdparty/Eigen/Eigen/src/Core/ArrayBase.h similarity index 75% rename from splinter/src/Core/ArrayBase.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/ArrayBase.h index 33ff553712..3dbc7084cd 100644 --- a/splinter/src/Core/ArrayBase.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/ArrayBase.h @@ -32,7 +32,7 @@ template class MatrixWrapper; * \tparam Derived is the derived type, e.g., an array or an expression type. * * 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_ARRAYBASE_PLUGIN. + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_ARRAYBASE_PLUGIN. * * \sa class MatrixBase, \ref TopicClassHierarchy */ @@ -47,13 +47,11 @@ template class ArrayBase typedef ArrayBase Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; typedef DenseBase Base; - using Base::operator*; using Base::RowsAtCompileTime; using Base::ColsAtCompileTime; using Base::SizeAtCompileTime; @@ -62,8 +60,7 @@ template class ArrayBase using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; - using Base::CoeffReadCost; - + using Base::derived; using Base::const_cast_derived; using Base::rows; @@ -83,25 +80,14 @@ template class ArrayBase #endif // not EIGEN_PARSED_BY_DOXYGEN #ifndef EIGEN_PARSED_BY_DOXYGEN - /** \internal the plain matrix type corresponding to this expression. Note that is not necessarily - * exactly the return type of eval(): in the case of plain matrices, the return type of eval() is a const - * reference to a matrix, not a matrix! It is however guaranteed that the return type of eval() is either - * PlainObject or const PlainObject&. - */ - typedef Array::Scalar, - internal::traits::RowsAtCompileTime, - internal::traits::ColsAtCompileTime, - AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), - internal::traits::MaxRowsAtCompileTime, - internal::traits::MaxColsAtCompileTime - > PlainObject; - + typedef typename Base::PlainObject PlainObject; /** \internal Represents a matrix with all coefficients equal to one another*/ - typedef CwiseNullaryOp,Derived> ConstantReturnType; + typedef CwiseNullaryOp,PlainObject> ConstantReturnType; #endif // not EIGEN_PARSED_BY_DOXYGEN #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::ArrayBase +#define EIGEN_DOC_UNARY_ADDONS(X,Y) # include "../plugins/CommonCwiseUnaryOps.h" # include "../plugins/MatrixCwiseUnaryOps.h" # include "../plugins/ArrayCwiseUnaryOps.h" @@ -112,44 +98,62 @@ template class ArrayBase # include EIGEN_ARRAYBASE_PLUGIN # endif #undef EIGEN_CURRENT_STORAGE_BASE_CLASS +#undef EIGEN_DOC_UNARY_ADDONS /** Special case of the template operator=, in order to prevent the compiler * from generating a default operator= (issue hit with g++ 4.1) */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const ArrayBase& other) { - return internal::assign_selector::run(derived(), other.derived()); + internal::call_assignment(derived(), other.derived()); + return derived(); } - - Derived& operator+=(const Scalar& scalar) - { return *this = derived() + scalar; } - Derived& operator-=(const Scalar& scalar) - { return *this = derived() - scalar; } + + /** Set all the entries to \a value. + * \sa DenseBase::setConstant(), DenseBase::fill() */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator=(const Scalar &value) + { Base::setConstant(value); return derived(); } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator+=(const Scalar& scalar); + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator-=(const Scalar& scalar); template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator+=(const ArrayBase& other); template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator-=(const ArrayBase& other); template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator*=(const ArrayBase& other); template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator/=(const ArrayBase& other); public: + EIGEN_DEVICE_FUNC ArrayBase& array() { return *this; } + EIGEN_DEVICE_FUNC const ArrayBase& array() const { return *this; } /** \returns an \link Eigen::MatrixBase Matrix \endlink expression of this array * \sa MatrixBase::array() */ - MatrixWrapper matrix() { return derived(); } - const MatrixWrapper matrix() const { return derived(); } + EIGEN_DEVICE_FUNC + MatrixWrapper matrix() { return MatrixWrapper(derived()); } + EIGEN_DEVICE_FUNC + const MatrixWrapper matrix() const { return MatrixWrapper(derived()); } // template // inline void evalTo(Dest& dst) const { dst = matrix(); } protected: + EIGEN_DEVICE_FUNC ArrayBase() : Base() {} private: @@ -171,11 +175,10 @@ template class ArrayBase */ template template -EIGEN_STRONG_INLINE Derived & +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived & ArrayBase::operator-=(const ArrayBase &other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::sub_assign_op()); return derived(); } @@ -185,11 +188,10 @@ ArrayBase::operator-=(const ArrayBase &other) */ template template -EIGEN_STRONG_INLINE Derived & +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived & ArrayBase::operator+=(const ArrayBase& other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::add_assign_op()); return derived(); } @@ -199,11 +201,10 @@ ArrayBase::operator+=(const ArrayBase& other) */ template template -EIGEN_STRONG_INLINE Derived & +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived & ArrayBase::operator*=(const ArrayBase& other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::mul_assign_op()); return derived(); } @@ -213,11 +214,10 @@ ArrayBase::operator*=(const ArrayBase& other) */ template template -EIGEN_STRONG_INLINE Derived & +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived & ArrayBase::operator/=(const ArrayBase& other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::div_assign_op()); return derived(); } diff --git a/splinter/src/Core/ArrayWrapper.h b/splinter/thirdparty/Eigen/Eigen/src/Core/ArrayWrapper.h similarity index 58% rename from splinter/src/Core/ArrayWrapper.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/ArrayWrapper.h index b4641e2a01..688aadd626 100644 --- a/splinter/src/Core/ArrayWrapper.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/ArrayWrapper.h @@ -32,7 +32,8 @@ struct traits > // Let's remove NestByRefBit enum { Flags0 = traits::type >::Flags, - Flags = Flags0 & ~NestByRefBit + LvalueBitFlag = is_lvalue::value ? LvalueBit : 0, + Flags = (Flags0 & ~(NestByRefBit | LvalueBit)) | LvalueBitFlag }; }; } @@ -44,6 +45,7 @@ class ArrayWrapper : public ArrayBase > typedef ArrayBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(ArrayWrapper) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ArrayWrapper) + typedef typename internal::remove_all::type NestedExpression; typedef typename internal::conditional< internal::is_lvalue::value, @@ -51,76 +53,45 @@ class ArrayWrapper : public ArrayBase > const Scalar >::type ScalarWithConstIfNotLvalue; - typedef typename internal::nested::type NestedExpressionType; + typedef typename internal::ref_selector::non_const_type NestedExpressionType; - inline ArrayWrapper(ExpressionType& matrix) : m_expression(matrix) {} + using Base::coeffRef; + EIGEN_DEVICE_FUNC + explicit EIGEN_STRONG_INLINE ArrayWrapper(ExpressionType& matrix) : m_expression(matrix) {} + + EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } - inline ScalarWithConstIfNotLvalue* data() { return m_expression.const_cast_derived().data(); } + EIGEN_DEVICE_FUNC + inline ScalarWithConstIfNotLvalue* data() { return m_expression.data(); } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return m_expression.data(); } - inline CoeffReturnType coeff(Index rowId, Index colId) const - { - return m_expression.coeff(rowId, colId); - } - - inline Scalar& coeffRef(Index rowId, Index colId) - { - return m_expression.const_cast_derived().coeffRef(rowId, colId); - } - + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const { - return m_expression.const_cast_derived().coeffRef(rowId, colId); - } - - inline CoeffReturnType coeff(Index index) const - { - return m_expression.coeff(index); - } - - inline Scalar& coeffRef(Index index) - { - return m_expression.const_cast_derived().coeffRef(index); + return m_expression.coeffRef(rowId, colId); } + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { - return m_expression.const_cast_derived().coeffRef(index); - } - - template - inline const PacketScalar packet(Index rowId, Index colId) const - { - return m_expression.template packet(rowId, colId); - } - - template - inline void writePacket(Index rowId, Index colId, const PacketScalar& val) - { - m_expression.const_cast_derived().template writePacket(rowId, colId, val); - } - - template - inline const PacketScalar packet(Index index) const - { - return m_expression.template packet(index); - } - - template - inline void writePacket(Index index, const PacketScalar& val) - { - m_expression.const_cast_derived().template writePacket(index, val); + return m_expression.coeffRef(index); } template + EIGEN_DEVICE_FUNC inline void evalTo(Dest& dst) const { dst = m_expression; } const typename internal::remove_all::type& + EIGEN_DEVICE_FUNC nestedExpression() const { return m_expression; @@ -128,10 +99,12 @@ class ArrayWrapper : public ArrayBase > /** Forwards the resizing request to the nested expression * \sa DenseBase::resize(Index) */ - void resize(Index newSize) { m_expression.const_cast_derived().resize(newSize); } + EIGEN_DEVICE_FUNC + void resize(Index newSize) { m_expression.resize(newSize); } /** Forwards the resizing request to the nested expression * \sa DenseBase::resize(Index,Index)*/ - void resize(Index nbRows, Index nbCols) { m_expression.const_cast_derived().resize(nbRows,nbCols); } + EIGEN_DEVICE_FUNC + void resize(Index rows, Index cols) { m_expression.resize(rows,cols); } protected: NestedExpressionType m_expression; @@ -157,7 +130,8 @@ struct traits > // Let's remove NestByRefBit enum { Flags0 = traits::type >::Flags, - Flags = Flags0 & ~NestByRefBit + LvalueBitFlag = is_lvalue::value ? LvalueBit : 0, + Flags = (Flags0 & ~(NestByRefBit | LvalueBit)) | LvalueBitFlag }; }; } @@ -169,6 +143,7 @@ class MatrixWrapper : public MatrixBase > typedef MatrixBase > Base; EIGEN_DENSE_PUBLIC_INTERFACE(MatrixWrapper) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(MatrixWrapper) + typedef typename internal::remove_all::type NestedExpression; typedef typename internal::conditional< internal::is_lvalue::value, @@ -176,72 +151,40 @@ class MatrixWrapper : public MatrixBase > const Scalar >::type ScalarWithConstIfNotLvalue; - typedef typename internal::nested::type NestedExpressionType; + typedef typename internal::ref_selector::non_const_type NestedExpressionType; - inline MatrixWrapper(ExpressionType& a_matrix) : m_expression(a_matrix) {} + using Base::coeffRef; + EIGEN_DEVICE_FUNC + explicit inline MatrixWrapper(ExpressionType& matrix) : m_expression(matrix) {} + + EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } - inline ScalarWithConstIfNotLvalue* data() { return m_expression.const_cast_derived().data(); } + EIGEN_DEVICE_FUNC + inline ScalarWithConstIfNotLvalue* data() { return m_expression.data(); } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return m_expression.data(); } - inline CoeffReturnType coeff(Index rowId, Index colId) const - { - return m_expression.coeff(rowId, colId); - } - - inline Scalar& coeffRef(Index rowId, Index colId) - { - return m_expression.const_cast_derived().coeffRef(rowId, colId); - } - + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const { return m_expression.derived().coeffRef(rowId, colId); } - inline CoeffReturnType coeff(Index index) const - { - return m_expression.coeff(index); - } - - inline Scalar& coeffRef(Index index) - { - return m_expression.const_cast_derived().coeffRef(index); - } - + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { - return m_expression.const_cast_derived().coeffRef(index); - } - - template - inline const PacketScalar packet(Index rowId, Index colId) const - { - return m_expression.template packet(rowId, colId); - } - - template - inline void writePacket(Index rowId, Index colId, const PacketScalar& val) - { - m_expression.const_cast_derived().template writePacket(rowId, colId, val); - } - - template - inline const PacketScalar packet(Index index) const - { - return m_expression.template packet(index); - } - - template - inline void writePacket(Index index, const PacketScalar& val) - { - m_expression.const_cast_derived().template writePacket(index, val); + return m_expression.coeffRef(index); } + EIGEN_DEVICE_FUNC const typename internal::remove_all::type& nestedExpression() const { @@ -250,10 +193,12 @@ class MatrixWrapper : public MatrixBase > /** Forwards the resizing request to the nested expression * \sa DenseBase::resize(Index) */ - void resize(Index newSize) { m_expression.const_cast_derived().resize(newSize); } + EIGEN_DEVICE_FUNC + void resize(Index newSize) { m_expression.resize(newSize); } /** Forwards the resizing request to the nested expression * \sa DenseBase::resize(Index,Index)*/ - void resize(Index nbRows, Index nbCols) { m_expression.const_cast_derived().resize(nbRows,nbCols); } + EIGEN_DEVICE_FUNC + void resize(Index rows, Index cols) { m_expression.resize(rows,cols); } protected: NestedExpressionType m_expression; diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/Assign.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Assign.h new file mode 100644 index 0000000000..53806ba33c --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Assign.h @@ -0,0 +1,90 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2007 Michael Olbrich +// Copyright (C) 2006-2010 Benoit Jacob +// 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_ASSIGN_H +#define EIGEN_ASSIGN_H + +namespace Eigen { + +template +template +EIGEN_STRONG_INLINE Derived& DenseBase + ::lazyAssign(const DenseBase& other) +{ + enum{ + SameType = internal::is_same::value + }; + + EIGEN_STATIC_ASSERT_LVALUE(Derived) + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived) + EIGEN_STATIC_ASSERT(SameType,YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + + eigen_assert(rows() == other.rows() && cols() == other.cols()); + internal::call_assignment_no_alias(derived(),other.derived()); + + return derived(); +} + +template +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) +{ + internal::call_assignment(derived(), other.derived()); + return derived(); +} + +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) +{ + internal::call_assignment(derived(), other.derived()); + return derived(); +} + +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const MatrixBase& other) +{ + internal::call_assignment(derived(), other.derived()); + return derived(); +} + +template +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const DenseBase& other) +{ + internal::call_assignment(derived(), other.derived()); + return derived(); +} + +template +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const EigenBase& other) +{ + internal::call_assignment(derived(), other.derived()); + return derived(); +} + +template +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const ReturnByValue& other) +{ + other.derived().evalTo(derived()); + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_ASSIGN_H diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/AssignEvaluator.h b/splinter/thirdparty/Eigen/Eigen/src/Core/AssignEvaluator.h new file mode 100644 index 0000000000..dbe435d86b --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/AssignEvaluator.h @@ -0,0 +1,935 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Benoit Jacob +// Copyright (C) 2011-2014 Gael Guennebaud +// Copyright (C) 2011-2012 Jitse Niesen +// +// 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_EVALUATOR_H +#define EIGEN_ASSIGN_EVALUATOR_H + +namespace Eigen { + +// This implementation is based on Assign.h + +namespace internal { + +/*************************************************************************** +* Part 1 : the logic deciding a strategy for traversal and unrolling * +***************************************************************************/ + +// copy_using_evaluator_traits is based on assign_traits + +template +struct copy_using_evaluator_traits +{ + typedef typename DstEvaluator::XprType Dst; + typedef typename Dst::Scalar DstScalar; + + enum { + DstFlags = DstEvaluator::Flags, + SrcFlags = SrcEvaluator::Flags + }; + +public: + enum { + DstAlignment = DstEvaluator::Alignment, + SrcAlignment = SrcEvaluator::Alignment, + DstHasDirectAccess = (DstFlags & DirectAccessBit) == DirectAccessBit, + JointAlignment = EIGEN_PLAIN_ENUM_MIN(DstAlignment,SrcAlignment) + }; + +private: + enum { + InnerSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::SizeAtCompileTime) + : int(DstFlags)&RowMajorBit ? int(Dst::ColsAtCompileTime) + : int(Dst::RowsAtCompileTime), + InnerMaxSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::MaxSizeAtCompileTime) + : int(DstFlags)&RowMajorBit ? int(Dst::MaxColsAtCompileTime) + : int(Dst::MaxRowsAtCompileTime), + OuterStride = int(outer_stride_at_compile_time::ret), + MaxSizeAtCompileTime = Dst::SizeAtCompileTime + }; + + // TODO distinguish between linear traversal and inner-traversals + typedef typename find_best_packet::type LinearPacketType; + typedef typename find_best_packet::type InnerPacketType; + + enum { + LinearPacketSize = unpacket_traits::size, + InnerPacketSize = unpacket_traits::size + }; + +public: + enum { + LinearRequiredAlignment = unpacket_traits::alignment, + InnerRequiredAlignment = unpacket_traits::alignment + }; + +private: + enum { + DstIsRowMajor = DstFlags&RowMajorBit, + SrcIsRowMajor = SrcFlags&RowMajorBit, + StorageOrdersAgree = (int(DstIsRowMajor) == int(SrcIsRowMajor)), + MightVectorize = bool(StorageOrdersAgree) + && (int(DstFlags) & int(SrcFlags) & ActualPacketAccessBit) + && bool(functor_traits::PacketAccess), + MayInnerVectorize = MightVectorize + && int(InnerSize)!=Dynamic && int(InnerSize)%int(InnerPacketSize)==0 + && int(OuterStride)!=Dynamic && int(OuterStride)%int(InnerPacketSize)==0 + && (EIGEN_UNALIGNED_VECTORIZE || int(JointAlignment)>=int(InnerRequiredAlignment)), + MayLinearize = bool(StorageOrdersAgree) && (int(DstFlags) & int(SrcFlags) & LinearAccessBit), + MayLinearVectorize = bool(MightVectorize) && bool(MayLinearize) && bool(DstHasDirectAccess) + && (EIGEN_UNALIGNED_VECTORIZE || (int(DstAlignment)>=int(LinearRequiredAlignment)) || MaxSizeAtCompileTime == Dynamic), + /* If the destination isn't aligned, we have to do runtime checks and we don't unroll, + so it's only good for large enough sizes. */ + MaySliceVectorize = bool(MightVectorize) && bool(DstHasDirectAccess) + && (int(InnerMaxSize)==Dynamic || int(InnerMaxSize)>=(EIGEN_UNALIGNED_VECTORIZE?InnerPacketSize:(3*InnerPacketSize))) + /* slice vectorization can be slow, so we only want it if the slices are big, which is + indicated by InnerMaxSize rather than InnerSize, think of the case of a dynamic block + in a fixed-size matrix + However, with EIGEN_UNALIGNED_VECTORIZE and unrolling, slice vectorization is still worth it */ + }; + +public: + enum { + Traversal = int(MayLinearVectorize) && (LinearPacketSize>InnerPacketSize) ? int(LinearVectorizedTraversal) + : int(MayInnerVectorize) ? int(InnerVectorizedTraversal) + : int(MayLinearVectorize) ? int(LinearVectorizedTraversal) + : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) + : int(MayLinearize) ? int(LinearTraversal) + : int(DefaultTraversal), + Vectorized = int(Traversal) == InnerVectorizedTraversal + || int(Traversal) == LinearVectorizedTraversal + || int(Traversal) == SliceVectorizedTraversal + }; + + typedef typename conditional::type PacketType; + +private: + enum { + ActualPacketSize = int(Traversal)==LinearVectorizedTraversal ? LinearPacketSize + : Vectorized ? InnerPacketSize + : 1, + UnrollingLimit = EIGEN_UNROLLING_LIMIT * ActualPacketSize, + MayUnrollCompletely = int(Dst::SizeAtCompileTime) != Dynamic + && int(Dst::SizeAtCompileTime) * (int(DstEvaluator::CoeffReadCost)+int(SrcEvaluator::CoeffReadCost)) <= int(UnrollingLimit), + MayUnrollInner = int(InnerSize) != Dynamic + && int(InnerSize) * (int(DstEvaluator::CoeffReadCost)+int(SrcEvaluator::CoeffReadCost)) <= int(UnrollingLimit) + }; + +public: + enum { + Unrolling = (int(Traversal) == int(InnerVectorizedTraversal) || int(Traversal) == int(DefaultTraversal)) + ? ( + int(MayUnrollCompletely) ? int(CompleteUnrolling) + : int(MayUnrollInner) ? int(InnerUnrolling) + : int(NoUnrolling) + ) + : int(Traversal) == int(LinearVectorizedTraversal) + ? ( bool(MayUnrollCompletely) && ( EIGEN_UNALIGNED_VECTORIZE || (int(DstAlignment)>=int(LinearRequiredAlignment))) + ? int(CompleteUnrolling) + : int(NoUnrolling) ) + : int(Traversal) == int(LinearTraversal) + ? ( bool(MayUnrollCompletely) ? int(CompleteUnrolling) + : int(NoUnrolling) ) +#if EIGEN_UNALIGNED_VECTORIZE + : int(Traversal) == int(SliceVectorizedTraversal) + ? ( bool(MayUnrollInner) ? int(InnerUnrolling) + : int(NoUnrolling) ) +#endif + : int(NoUnrolling) + }; + +#ifdef EIGEN_DEBUG_ASSIGN + static void debug() + { + std::cerr << "DstXpr: " << typeid(typename DstEvaluator::XprType).name() << std::endl; + std::cerr << "SrcXpr: " << typeid(typename SrcEvaluator::XprType).name() << std::endl; + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "DstFlags" << " = " << DstFlags << " (" << demangle_flags(DstFlags) << " )" << std::endl; + std::cerr << "SrcFlags" << " = " << SrcFlags << " (" << demangle_flags(SrcFlags) << " )" << std::endl; + std::cerr.unsetf(std::ios::hex); + EIGEN_DEBUG_VAR(DstAlignment) + EIGEN_DEBUG_VAR(SrcAlignment) + EIGEN_DEBUG_VAR(LinearRequiredAlignment) + EIGEN_DEBUG_VAR(InnerRequiredAlignment) + EIGEN_DEBUG_VAR(JointAlignment) + EIGEN_DEBUG_VAR(InnerSize) + EIGEN_DEBUG_VAR(InnerMaxSize) + EIGEN_DEBUG_VAR(LinearPacketSize) + EIGEN_DEBUG_VAR(InnerPacketSize) + EIGEN_DEBUG_VAR(ActualPacketSize) + EIGEN_DEBUG_VAR(StorageOrdersAgree) + EIGEN_DEBUG_VAR(MightVectorize) + EIGEN_DEBUG_VAR(MayLinearize) + EIGEN_DEBUG_VAR(MayInnerVectorize) + EIGEN_DEBUG_VAR(MayLinearVectorize) + EIGEN_DEBUG_VAR(MaySliceVectorize) + std::cerr << "Traversal" << " = " << Traversal << " (" << demangle_traversal(Traversal) << ")" << std::endl; + EIGEN_DEBUG_VAR(SrcEvaluator::CoeffReadCost) + EIGEN_DEBUG_VAR(UnrollingLimit) + EIGEN_DEBUG_VAR(MayUnrollCompletely) + EIGEN_DEBUG_VAR(MayUnrollInner) + std::cerr << "Unrolling" << " = " << Unrolling << " (" << demangle_unrolling(Unrolling) << ")" << std::endl; + std::cerr << std::endl; + } +#endif +}; + +/*************************************************************************** +* Part 2 : meta-unrollers +***************************************************************************/ + +/************************ +*** Default traversal *** +************************/ + +template +struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling +{ + // FIXME: this is not very clean, perhaps this information should be provided by the kernel? + typedef typename Kernel::DstEvaluatorType DstEvaluatorType; + typedef typename DstEvaluatorType::XprType DstXprType; + + enum { + outer = Index / DstXprType::InnerSizeAtCompileTime, + inner = Index % DstXprType::InnerSizeAtCompileTime + }; + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + kernel.assignCoeffByOuterInner(outer, inner); + copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); + } +}; + +template +struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } +}; + +template +struct copy_using_evaluator_DefaultTraversal_InnerUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, Index outer) + { + kernel.assignCoeffByOuterInner(outer, Index_); + copy_using_evaluator_DefaultTraversal_InnerUnrolling::run(kernel, outer); + } +}; + +template +struct copy_using_evaluator_DefaultTraversal_InnerUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&, Index) { } +}; + +/*********************** +*** Linear traversal *** +***********************/ + +template +struct copy_using_evaluator_LinearTraversal_CompleteUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel& kernel) + { + kernel.assignCoeff(Index); + copy_using_evaluator_LinearTraversal_CompleteUnrolling::run(kernel); + } +}; + +template +struct copy_using_evaluator_LinearTraversal_CompleteUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } +}; + +/************************** +*** Inner vectorization *** +**************************/ + +template +struct copy_using_evaluator_innervec_CompleteUnrolling +{ + // FIXME: this is not very clean, perhaps this information should be provided by the kernel? + typedef typename Kernel::DstEvaluatorType DstEvaluatorType; + typedef typename DstEvaluatorType::XprType DstXprType; + typedef typename Kernel::PacketType PacketType; + + enum { + outer = Index / DstXprType::InnerSizeAtCompileTime, + inner = Index % DstXprType::InnerSizeAtCompileTime, + SrcAlignment = Kernel::AssignmentTraits::SrcAlignment, + DstAlignment = Kernel::AssignmentTraits::DstAlignment + }; + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + kernel.template assignPacketByOuterInner(outer, inner); + enum { NextIndex = Index + unpacket_traits::size }; + copy_using_evaluator_innervec_CompleteUnrolling::run(kernel); + } +}; + +template +struct copy_using_evaluator_innervec_CompleteUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } +}; + +template +struct copy_using_evaluator_innervec_InnerUnrolling +{ + typedef typename Kernel::PacketType PacketType; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, Index outer) + { + kernel.template assignPacketByOuterInner(outer, Index_); + enum { NextIndex = Index_ + unpacket_traits::size }; + copy_using_evaluator_innervec_InnerUnrolling::run(kernel, outer); + } +}; + +template +struct copy_using_evaluator_innervec_InnerUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &, Index) { } +}; + +/*************************************************************************** +* Part 3 : implementation of all cases +***************************************************************************/ + +// dense_assignment_loop is based on assign_impl + +template +struct dense_assignment_loop; + +/************************ +*** Default traversal *** +************************/ + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static void EIGEN_STRONG_INLINE run(Kernel &kernel) + { + for(Index outer = 0; outer < kernel.outerSize(); ++outer) { + for(Index inner = 0; inner < kernel.innerSize(); ++inner) { + kernel.assignCoeffByOuterInner(outer, inner); + } + } + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + + const Index outerSize = kernel.outerSize(); + for(Index outer = 0; outer < outerSize; ++outer) + copy_using_evaluator_DefaultTraversal_InnerUnrolling::run(kernel, outer); + } +}; + +/*************************** +*** Linear vectorization *** +***************************/ + + +// The goal of unaligned_dense_assignment_loop is simply to factorize the handling +// of the non vectorizable beginning and ending parts + +template +struct unaligned_dense_assignment_loop +{ + // if IsAligned = true, then do nothing + template + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&, Index, Index) {} +}; + +template <> +struct unaligned_dense_assignment_loop +{ + // MSVC must not inline this functions. If it does, it fails to optimize the + // packet access path. + // FIXME check which version exhibits this issue +#if EIGEN_COMP_MSVC + template + static EIGEN_DONT_INLINE void run(Kernel &kernel, + Index start, + Index end) +#else + template + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, + Index start, + Index end) +#endif + { + for (Index index = start; index < end; ++index) + kernel.assignCoeff(index); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + const Index size = kernel.size(); + typedef typename Kernel::Scalar Scalar; + typedef typename Kernel::PacketType PacketType; + enum { + requestedAlignment = Kernel::AssignmentTraits::LinearRequiredAlignment, + packetSize = unpacket_traits::size, + dstIsAligned = int(Kernel::AssignmentTraits::DstAlignment)>=int(requestedAlignment), + dstAlignment = packet_traits::AlignedOnScalar ? int(requestedAlignment) + : int(Kernel::AssignmentTraits::DstAlignment), + srcAlignment = Kernel::AssignmentTraits::JointAlignment + }; + const Index alignedStart = dstIsAligned ? 0 : internal::first_aligned(kernel.dstDataPtr(), size); + const Index alignedEnd = alignedStart + ((size-alignedStart)/packetSize)*packetSize; + + unaligned_dense_assignment_loop::run(kernel, 0, alignedStart); + + for(Index index = alignedStart; index < alignedEnd; index += packetSize) + kernel.template assignPacket(index); + + unaligned_dense_assignment_loop<>::run(kernel, alignedEnd, size); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + typedef typename Kernel::PacketType PacketType; + + enum { size = DstXprType::SizeAtCompileTime, + packetSize =unpacket_traits::size, + alignedSize = (size/packetSize)*packetSize }; + + copy_using_evaluator_innervec_CompleteUnrolling::run(kernel); + copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); + } +}; + +/************************** +*** Inner vectorization *** +**************************/ + +template +struct dense_assignment_loop +{ + typedef typename Kernel::PacketType PacketType; + enum { + SrcAlignment = Kernel::AssignmentTraits::SrcAlignment, + DstAlignment = Kernel::AssignmentTraits::DstAlignment + }; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + const Index innerSize = kernel.innerSize(); + const Index outerSize = kernel.outerSize(); + const Index packetSize = unpacket_traits::size; + for(Index outer = 0; outer < outerSize; ++outer) + for(Index inner = 0; inner < innerSize; inner+=packetSize) + kernel.template assignPacketByOuterInner(outer, inner); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + copy_using_evaluator_innervec_CompleteUnrolling::run(kernel); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + typedef typename Kernel::AssignmentTraits Traits; + const Index outerSize = kernel.outerSize(); + for(Index outer = 0; outer < outerSize; ++outer) + copy_using_evaluator_innervec_InnerUnrolling::run(kernel, outer); + } +}; + +/*********************** +*** Linear traversal *** +***********************/ + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + const Index size = kernel.size(); + for(Index i = 0; i < size; ++i) + kernel.assignCoeff(i); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + copy_using_evaluator_LinearTraversal_CompleteUnrolling::run(kernel); + } +}; + +/************************** +*** Slice vectorization *** +***************************/ + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::Scalar Scalar; + typedef typename Kernel::PacketType PacketType; + enum { + packetSize = unpacket_traits::size, + requestedAlignment = int(Kernel::AssignmentTraits::InnerRequiredAlignment), + alignable = packet_traits::AlignedOnScalar || int(Kernel::AssignmentTraits::DstAlignment)>=sizeof(Scalar), + dstIsAligned = int(Kernel::AssignmentTraits::DstAlignment)>=int(requestedAlignment), + dstAlignment = alignable ? int(requestedAlignment) + : int(Kernel::AssignmentTraits::DstAlignment) + }; + const Scalar *dst_ptr = kernel.dstDataPtr(); + if((!bool(dstIsAligned)) && (UIntPtr(dst_ptr) % sizeof(Scalar))>0) + { + // the pointer is not aligend-on scalar, so alignment is not possible + return dense_assignment_loop::run(kernel); + } + const Index packetAlignedMask = packetSize - 1; + const Index innerSize = kernel.innerSize(); + const Index outerSize = kernel.outerSize(); + const Index alignedStep = alignable ? (packetSize - kernel.outerStride() % packetSize) & packetAlignedMask : 0; + Index alignedStart = ((!alignable) || bool(dstIsAligned)) ? 0 : internal::first_aligned(dst_ptr, innerSize); + + for(Index outer = 0; outer < outerSize; ++outer) + { + const Index alignedEnd = alignedStart + ((innerSize-alignedStart) & ~packetAlignedMask); + // do the non-vectorizable part of the assignment + for(Index inner = 0; inner(outer, inner); + + // do the non-vectorizable part of the assignment + for(Index inner = alignedEnd; inner +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + typedef typename Kernel::PacketType PacketType; + + enum { size = DstXprType::InnerSizeAtCompileTime, + packetSize =unpacket_traits::size, + vectorizableSize = (size/packetSize)*packetSize }; + + for(Index outer = 0; outer < kernel.outerSize(); ++outer) + { + copy_using_evaluator_innervec_InnerUnrolling::run(kernel, outer); + copy_using_evaluator_DefaultTraversal_InnerUnrolling::run(kernel, outer); + } + } +}; +#endif + + +/*************************************************************************** +* Part 4 : Generic dense assignment kernel +***************************************************************************/ + +// This class generalize the assignment of a coefficient (or packet) from one dense evaluator +// to another dense writable evaluator. +// It is parametrized by the two evaluators, and the actual assignment functor. +// This abstraction level permits to keep the evaluation loops as simple and as generic as possible. +// One can customize the assignment using this generic dense_assignment_kernel with different +// functors, or by completely overloading it, by-passing a functor. +template +class generic_dense_assignment_kernel +{ +protected: + typedef typename DstEvaluatorTypeT::XprType DstXprType; + typedef typename SrcEvaluatorTypeT::XprType SrcXprType; +public: + + typedef DstEvaluatorTypeT DstEvaluatorType; + typedef SrcEvaluatorTypeT SrcEvaluatorType; + typedef typename DstEvaluatorType::Scalar Scalar; + typedef copy_using_evaluator_traits AssignmentTraits; + typedef typename AssignmentTraits::PacketType PacketType; + + + EIGEN_DEVICE_FUNC generic_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) + : m_dst(dst), m_src(src), m_functor(func), m_dstExpr(dstExpr) + { + #ifdef EIGEN_DEBUG_ASSIGN + AssignmentTraits::debug(); + #endif + } + + EIGEN_DEVICE_FUNC Index size() const { return m_dstExpr.size(); } + EIGEN_DEVICE_FUNC Index innerSize() const { return m_dstExpr.innerSize(); } + EIGEN_DEVICE_FUNC Index outerSize() const { return m_dstExpr.outerSize(); } + EIGEN_DEVICE_FUNC Index rows() const { return m_dstExpr.rows(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_dstExpr.cols(); } + EIGEN_DEVICE_FUNC Index outerStride() const { return m_dstExpr.outerStride(); } + + EIGEN_DEVICE_FUNC DstEvaluatorType& dstEvaluator() { return m_dst; } + EIGEN_DEVICE_FUNC const SrcEvaluatorType& srcEvaluator() const { return m_src; } + + /// Assign src(row,col) to dst(row,col) through the assignment functor. + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Index row, Index col) + { + m_functor.assignCoeff(m_dst.coeffRef(row,col), m_src.coeff(row,col)); + } + + /// \sa assignCoeff(Index,Index) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Index index) + { + m_functor.assignCoeff(m_dst.coeffRef(index), m_src.coeff(index)); + } + + /// \sa assignCoeff(Index,Index) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeffByOuterInner(Index outer, Index inner) + { + Index row = rowIndexByOuterInner(outer, inner); + Index col = colIndexByOuterInner(outer, inner); + assignCoeff(row, col); + } + + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacket(Index row, Index col) + { + m_functor.template assignPacket(&m_dst.coeffRef(row,col), m_src.template packet(row,col)); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacket(Index index) + { + m_functor.template assignPacket(&m_dst.coeffRef(index), m_src.template packet(index)); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacketByOuterInner(Index outer, Index inner) + { + Index row = rowIndexByOuterInner(outer, inner); + Index col = colIndexByOuterInner(outer, inner); + assignPacket(row, col); + } + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner) + { + typedef typename DstEvaluatorType::ExpressionTraits Traits; + return int(Traits::RowsAtCompileTime) == 1 ? 0 + : int(Traits::ColsAtCompileTime) == 1 ? inner + : int(DstEvaluatorType::Flags)&RowMajorBit ? outer + : inner; + } + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Index colIndexByOuterInner(Index outer, Index inner) + { + typedef typename DstEvaluatorType::ExpressionTraits Traits; + return int(Traits::ColsAtCompileTime) == 1 ? 0 + : int(Traits::RowsAtCompileTime) == 1 ? inner + : int(DstEvaluatorType::Flags)&RowMajorBit ? inner + : outer; + } + + EIGEN_DEVICE_FUNC const Scalar* dstDataPtr() const + { + return m_dstExpr.data(); + } + +protected: + DstEvaluatorType& m_dst; + const SrcEvaluatorType& m_src; + const Functor &m_functor; + // TODO find a way to avoid the needs of the original expression + DstXprType& m_dstExpr; +}; + +/*************************************************************************** +* Part 5 : Entry point for dense rectangular assignment +***************************************************************************/ + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const Functor &/*func*/) +{ + EIGEN_ONLY_USED_FOR_DEBUG(dst); + EIGEN_ONLY_USED_FOR_DEBUG(src); + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const internal::assign_op &/*func*/) +{ + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if(((dst.rows()!=dstRows) || (dst.cols()!=dstCols))) + dst.resize(dstRows, dstCols); + eigen_assert(dst.rows() == dstRows && dst.cols() == dstCols); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_dense_assignment_loop(DstXprType& dst, const SrcXprType& src, const Functor &func) +{ + typedef evaluator DstEvaluatorType; + typedef evaluator SrcEvaluatorType; + + SrcEvaluatorType srcEvaluator(src); + + // NOTE To properly handle A = (A*A.transpose())/s with A rectangular, + // we need to resize the destination after the source evaluator has been created. + resize_if_allowed(dst, src, func); + + DstEvaluatorType dstEvaluator(dst); + + typedef generic_dense_assignment_kernel Kernel; + Kernel kernel(dstEvaluator, srcEvaluator, func, dst.const_cast_derived()); + + dense_assignment_loop::run(kernel); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_dense_assignment_loop(DstXprType& dst, const SrcXprType& src) +{ + call_dense_assignment_loop(dst, src, internal::assign_op()); +} + +/*************************************************************************** +* Part 6 : Generic assignment +***************************************************************************/ + +// Based on the respective shapes of the destination and source, +// the class AssignmentKind determine the kind of assignment mechanism. +// AssignmentKind must define a Kind typedef. +template struct AssignmentKind; + +// Assignement kind defined in this file: +struct Dense2Dense {}; +struct EigenBase2EigenBase {}; + +template struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; +template<> struct AssignmentKind { typedef Dense2Dense Kind; }; + +// This is the main assignment class +template< typename DstXprType, typename SrcXprType, typename Functor, + typename Kind = typename AssignmentKind< typename evaluator_traits::Shape , typename evaluator_traits::Shape >::Kind, + typename EnableIf = void> +struct Assignment; + + +// The only purpose of this call_assignment() function is to deal with noalias() / "assume-aliasing" and automatic transposition. +// Indeed, I (Gael) think that this concept of "assume-aliasing" was a mistake, and it makes thing quite complicated. +// So this intermediate function removes everything related to "assume-aliasing" such that Assignment +// does not has to bother about these annoying details. + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment(Dst& dst, const Src& src) +{ + call_assignment(dst, src, internal::assign_op()); +} +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment(const Dst& dst, const Src& src) +{ + call_assignment(dst, src, internal::assign_op()); +} + +// Deal with "assume-aliasing" +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if< evaluator_assume_aliasing::value, void*>::type = 0) +{ + typename plain_matrix_type::type tmp(src); + call_assignment_no_alias(dst, tmp, func); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::value, void*>::type = 0) +{ + call_assignment_no_alias(dst, src, func); +} + +// by-pass "assume-aliasing" +// When there is no aliasing, we require that 'dst' has been properly resized +template class StorageBase, typename Src, typename Func> +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment(NoAlias& dst, const Src& src, const Func& func) +{ + call_assignment_no_alias(dst.expression(), src, func); +} + + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) +{ + enum { + NeedToTranspose = ( (int(Dst::RowsAtCompileTime) == 1 && int(Src::ColsAtCompileTime) == 1) + || (int(Dst::ColsAtCompileTime) == 1 && int(Src::RowsAtCompileTime) == 1) + ) && int(Dst::SizeAtCompileTime) != 1 + }; + + typedef typename internal::conditional, Dst>::type ActualDstTypeCleaned; + typedef typename internal::conditional, Dst&>::type ActualDstType; + ActualDstType actualDst(dst); + + // TODO check whether this is the right place to perform these checks: + EIGEN_STATIC_ASSERT_LVALUE(Dst) + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(ActualDstTypeCleaned,Src) + EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename ActualDstTypeCleaned::Scalar,typename Src::Scalar); + + Assignment::run(actualDst, src, func); +} +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment_no_alias(Dst& dst, const Src& src) +{ + call_assignment_no_alias(dst, src, internal::assign_op()); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment_no_alias_no_transpose(Dst& dst, const Src& src, const Func& func) +{ + // TODO check whether this is the right place to perform these checks: + EIGEN_STATIC_ASSERT_LVALUE(Dst) + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Dst,Src) + EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename Dst::Scalar,typename Src::Scalar); + + Assignment::run(dst, src, func); +} +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment_no_alias_no_transpose(Dst& dst, const Src& src) +{ + call_assignment_no_alias_no_transpose(dst, src, internal::assign_op()); +} + +// forward declaration +template void check_for_aliasing(const Dst &dst, const Src &src); + +// Generic Dense to Dense assignment +// Note that the last template argument "Weak" is needed to make it possible to perform +// both partial specialization+SFINAE without ambiguous specialization +template< typename DstXprType, typename SrcXprType, typename Functor, typename Weak> +struct Assignment +{ + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const Functor &func) + { +#ifndef EIGEN_NO_DEBUG + internal::check_for_aliasing(dst, src); +#endif + + call_dense_assignment_loop(dst, src, func); + } +}; + +// Generic assignment through evalTo. +// TODO: not sure we have to keep that one, but it helps porting current code to new evaluator mechanism. +// Note that the last template argument "Weak" is needed to make it possible to perform +// both partial specialization+SFINAE without ambiguous specialization +template< typename DstXprType, typename SrcXprType, typename Functor, typename Weak> +struct Assignment +{ + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + src.evalTo(dst); + } + + // NOTE The following two functions are templated to avoid their instanciation if not needed + // This is needed because some expressions supports evalTo only and/or have 'void' as scalar type. + template + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &/*func*/) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + src.addTo(dst); + } + + template + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &/*func*/) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + src.subTo(dst); + } +}; + +} // namespace internal + +} // end namespace Eigen + +#endif // EIGEN_ASSIGN_EVALUATOR_H diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/Assign_MKL.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Assign_MKL.h new file mode 100755 index 0000000000..6866095bf8 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Assign_MKL.h @@ -0,0 +1,178 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + Copyright (C) 2015 Gael Guennebaud + + 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 +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 = 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 + }; + public: + enum { + EnableVml = MightEnableVml && LargeEnough, + Traversal = MightLinearize ? LinearTraversal : DefaultTraversal + }; +}; + +#define EIGEN_PP_EXPAND(ARG) ARG +#if !defined (EIGEN_FAST_MATH) || (EIGEN_FAST_MATH != 1) +#define EIGEN_VMLMODE_EXPAND_LA , VML_HA +#else +#define EIGEN_VMLMODE_EXPAND_LA , VML_LA +#endif + +#define EIGEN_VMLMODE_EXPAND__ + +#define EIGEN_VMLMODE_PREFIX_LA vm +#define EIGEN_VMLMODE_PREFIX__ v +#define EIGEN_VMLMODE_PREFIX(VMLMODE) EIGEN_CAT(EIGEN_VMLMODE_PREFIX_,VMLMODE) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE, VMLMODE) \ + template< typename DstXprType, typename SrcXprNested> \ + struct Assignment, SrcXprNested>, assign_op, \ + Dense2Dense, typename enable_if::EnableVml>::type> { \ + typedef CwiseUnaryOp, SrcXprNested> SrcXprType; \ + static void run(DstXprType &dst, const SrcXprType &src, const assign_op &func) { \ + resize_if_allowed(dst, src, func); \ + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); \ + if(vml_assign_traits::Traversal==LinearTraversal) { \ + VMLOP(dst.size(), (const VMLTYPE*)src.nestedExpression().data(), \ + (VMLTYPE*)dst.data() EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_##VMLMODE) ); \ + } else { \ + const Index outerSize = dst.outerSize(); \ + for(Index outer = 0; outer < outerSize; ++outer) { \ + const EIGENTYPE *src_ptr = src.IsRowMajor ? &(src.nestedExpression().coeffRef(outer,0)) : \ + &(src.nestedExpression().coeffRef(0, outer)); \ + EIGENTYPE *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer,0)) : &(dst.coeffRef(0, outer)); \ + VMLOP( dst.innerSize(), (const VMLTYPE*)src_ptr, \ + (VMLTYPE*)dst_ptr EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_##VMLMODE)); \ + } \ + } \ + } \ + }; \ + + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),s##VMLOP), float, float, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),d##VMLOP), double, double, VMLMODE) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(EIGENOP, VMLOP, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),c##VMLOP), scomplex, MKL_Complex8, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),z##VMLOP), dcomplex, MKL_Complex16, VMLMODE) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS(EIGENOP, VMLOP, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(EIGENOP, VMLOP, VMLMODE) + + +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sin, Sin, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(asin, Asin, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sinh, Sinh, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(cos, Cos, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(acos, Acos, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(cosh, Cosh, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(tan, Tan, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(atan, Atan, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(tanh, Tanh, LA) +// EIGEN_MKL_VML_DECLARE_UNARY_CALLS(abs, Abs, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(exp, Exp, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(log, Ln, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(log10, Log10, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sqrt, Sqrt, _) + +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(square, Sqr, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(arg, Arg, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(round, Round, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(floor, Floor, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(ceil, Ceil, _) + +#define EIGEN_MKL_VML_DECLARE_POW_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE, VMLMODE) \ + template< typename DstXprType, typename SrcXprNested, typename Plain> \ + struct Assignment, SrcXprNested, \ + const CwiseNullaryOp,Plain> >, assign_op, \ + Dense2Dense, typename enable_if::EnableVml>::type> { \ + typedef CwiseBinaryOp, SrcXprNested, \ + const CwiseNullaryOp,Plain> > SrcXprType; \ + static void run(DstXprType &dst, const SrcXprType &src, const assign_op &func) { \ + resize_if_allowed(dst, src, func); \ + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); \ + VMLTYPE exponent = reinterpret_cast(src.rhs().functor().m_other); \ + if(vml_assign_traits::Traversal==LinearTraversal) \ + { \ + VMLOP( dst.size(), (const VMLTYPE*)src.lhs().data(), exponent, \ + (VMLTYPE*)dst.data() EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_##VMLMODE) ); \ + } else { \ + const Index outerSize = dst.outerSize(); \ + for(Index outer = 0; outer < outerSize; ++outer) { \ + const EIGENTYPE *src_ptr = src.IsRowMajor ? &(src.lhs().coeffRef(outer,0)) : \ + &(src.lhs().coeffRef(0, outer)); \ + EIGENTYPE *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer,0)) : &(dst.coeffRef(0, outer)); \ + VMLOP( dst.innerSize(), (const VMLTYPE*)src_ptr, exponent, \ + (VMLTYPE*)dst_ptr EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_##VMLMODE)); \ + } \ + } \ + } \ + }; + +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmsPowx, float, float, LA) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmdPowx, double, double, LA) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmcPowx, scomplex, MKL_Complex8, LA) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmzPowx, dcomplex, MKL_Complex16, LA) + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_ASSIGN_VML_H diff --git a/splinter/src/Core/BandMatrix.h b/splinter/thirdparty/Eigen/Eigen/src/Core/BandMatrix.h similarity index 83% rename from splinter/src/Core/BandMatrix.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/BandMatrix.h index ffd7fe8b30..4978c91405 100644 --- a/splinter/src/Core/BandMatrix.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/BandMatrix.h @@ -32,7 +32,7 @@ class BandMatrixBase : public EigenBase }; typedef typename internal::traits::Scalar Scalar; typedef Matrix DenseMatrixType; - typedef typename DenseMatrixType::Index Index; + typedef typename DenseMatrixType::StorageIndex StorageIndex; typedef typename internal::traits::CoefficientsType CoefficientsType; typedef EigenBase Base; @@ -161,15 +161,15 @@ class BandMatrixBase : public EigenBase * * \brief Represents a rectangular matrix with a banded storage * - * \param _Scalar Numeric type, i.e. float, double, int - * \param Rows Number of rows, or \b Dynamic - * \param Cols Number of columns, or \b Dynamic - * \param Supers Number of super diagonal - * \param Subs Number of sub diagonal - * \param _Options A combination of either \b #RowMajor or \b #ColMajor, and of \b #SelfAdjoint - * The former controls \ref TopicStorageOrders "storage order", and defaults to - * column-major. The latter controls whether the matrix represents a selfadjoint - * matrix in which case either Supers of Subs have to be null. + * \tparam _Scalar Numeric type, i.e. float, double, int + * \tparam _Rows Number of rows, or \b Dynamic + * \tparam _Cols Number of columns, or \b Dynamic + * \tparam _Supers Number of super diagonal + * \tparam _Subs Number of sub diagonal + * \tparam _Options A combination of either \b #RowMajor or \b #ColMajor, and of \b #SelfAdjoint + * The former controls \ref TopicStorageOrders "storage order", and defaults to + * column-major. The latter controls whether the matrix represents a selfadjoint + * matrix in which case either Supers of Subs have to be null. * * \sa class TridiagonalMatrix */ @@ -179,7 +179,7 @@ struct traits > { typedef _Scalar Scalar; typedef Dense StorageKind; - typedef DenseIndex Index; + typedef Eigen::Index StorageIndex; enum { CoeffReadCost = NumTraits::ReadCost, RowsAtCompileTime = _Rows, @@ -201,10 +201,10 @@ class BandMatrix : public BandMatrixBase::Scalar Scalar; - typedef typename internal::traits::Index Index; + typedef typename internal::traits::StorageIndex StorageIndex; typedef typename internal::traits::CoefficientsType CoefficientsType; - inline BandMatrix(Index rows=Rows, Index cols=Cols, Index supers=Supers, Index subs=Subs) + explicit inline BandMatrix(Index rows=Rows, Index cols=Cols, Index supers=Supers, Index subs=Subs) : m_coeffs(1+supers+subs,cols), m_rows(rows), m_supers(supers), m_subs(subs) { @@ -241,7 +241,7 @@ struct traits::CoeffReadCost, RowsAtCompileTime = _Rows, @@ -264,9 +264,9 @@ class BandMatrixWrapper : public BandMatrixBase::Scalar Scalar; typedef typename internal::traits::CoefficientsType CoefficientsType; - typedef typename internal::traits::Index Index; + typedef typename internal::traits::StorageIndex StorageIndex; - inline BandMatrixWrapper(const CoefficientsType& coeffs, Index rows=_Rows, Index cols=_Cols, Index supers=_Supers, Index subs=_Subs) + explicit inline BandMatrixWrapper(const CoefficientsType& coeffs, Index rows=_Rows, Index cols=_Cols, Index supers=_Supers, Index subs=_Subs) : m_coeffs(coeffs), m_rows(rows), m_supers(supers), m_subs(subs) { @@ -302,9 +302,9 @@ class BandMatrixWrapper : public BandMatrixBase class TridiagonalMatrix : public BandMatrix { typedef BandMatrix Base; - typedef typename Base::Index Index; + typedef typename Base::StorageIndex StorageIndex; public: - TridiagonalMatrix(Index size = Size) : Base(size,size,Options&SelfAdjoint?0:1,1) {} + explicit TridiagonalMatrix(Index size = Size) : Base(size,size,Options&SelfAdjoint?0:1,1) {} inline typename Base::template DiagonalIntReturnType<1>::Type super() { return Base::template diagonal<1>(); } @@ -327,6 +327,25 @@ class TridiagonalMatrix : public BandMatrix +struct evaluator_traits > + : public evaluator_traits_base > +{ + typedef BandShape Shape; +}; + +template +struct evaluator_traits > + : public evaluator_traits_base > +{ + typedef BandShape Shape; +}; + +template<> struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; + } // end namespace internal } // end namespace Eigen diff --git a/splinter/src/Core/Block.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Block.h similarity index 61% rename from splinter/src/Core/Block.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/Block.h index 8278944432..11de45c2ec 100644 --- a/splinter/src/Core/Block.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Block.h @@ -13,38 +13,6 @@ namespace Eigen { -/** \class Block - * \ingroup Core_Module - * - * \brief Expression of a fixed-size or dynamic-size block - * - * \param XprType the type of the expression in which we are taking a block - * \param BlockRows the number of rows of the block we are taking at compile time (optional) - * \param BlockCols the number of columns of the block we are taking at compile time (optional) - * - * This class represents an expression of either a fixed-size or dynamic-size block. It is the return - * type of DenseBase::block(Index,Index,Index,Index) and DenseBase::block(Index,Index) and - * most of the time this is the only way it is used. - * - * However, if you want to directly maniputate block expressions, - * for instance if you want to write a function returning such an expression, you - * will need to use this class. - * - * Here is an example illustrating the dynamic case: - * \include class_Block.cpp - * Output: \verbinclude class_Block.out - * - * \note Even though this expression has dynamic size, in the case where \a XprType - * has fixed size, this expression inherits a fixed maximal size which means that evaluating - * it does not cause a dynamic memory allocation. - * - * Here is an example illustrating the fixed-size case: - * \include class_FixedBlock.cpp - * Output: \verbinclude class_FixedBlock.out - * - * \sa DenseBase::block(Index,Index,Index,Index), DenseBase::block(Index,Index), class VectorBlock - */ - namespace internal { template struct traits > : traits @@ -52,7 +20,7 @@ struct traits > : traits::Scalar Scalar; typedef typename traits::StorageKind StorageKind; typedef typename traits::XprKind XprKind; - typedef typename nested::type XprTypeNested; + typedef typename ref_selector::type XprTypeNested; typedef typename remove_reference::type _XprTypeNested; enum{ MatrixRows = traits::RowsAtCompileTime, @@ -65,10 +33,10 @@ struct traits > : traits::MaxColsAtCompileTime), + XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0, - IsDense = is_same::value, - IsRowMajor = (IsDense&&MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 - : (IsDense&&MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 + IsRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 : XprTypeIsRowMajor, HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor), InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime), @@ -78,18 +46,16 @@ struct traits > : traits::ret) : int(inner_stride_at_compile_time::ret), - MaskPacketAccessBit = (InnerSize == Dynamic || (InnerSize % packet_traits::size) == 0) - && (InnerStrideAtCompileTime == 1) - ? PacketAccessBit : 0, - MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % 16) == 0)) ? AlignedBit : 0, - FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (traits::Flags&LinearAccessBit))) ? LinearAccessBit : 0, + + // FIXME, this traits is rather specialized for dense object and it needs to be cleaned further FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, - Flags0 = traits::Flags & ( (HereditaryBits & ~RowMajorBit) | - DirectAccessBit | - MaskPacketAccessBit | - MaskAlignedBit), - Flags = Flags0 | FlagsLinearAccessBit | FlagsLvalueBit | FlagsRowMajorBit + Flags = (traits::Flags & (DirectAccessBit | (InnerPanel?CompressedAccessBit:0))) | FlagsLvalueBit | FlagsRowMajorBit, + // FIXME DirectAccessBit should not be handled by expressions + // + // Alignment is needed by MapBase's assertions + // We can sefely set it to false here. Internal alignment errors will be detected by an eigen_internal_assert in the respective evaluator + Alignment = 0 }; }; @@ -100,6 +66,40 @@ template class BlockImpl; +/** \class Block + * \ingroup Core_Module + * + * \brief Expression of a fixed-size or dynamic-size block + * + * \tparam XprType the type of the expression in which we are taking a block + * \tparam BlockRows the number of rows of the block we are taking at compile time (optional) + * \tparam BlockCols the number of columns of the block we are taking at compile time (optional) + * \tparam InnerPanel is true, if the block maps to a set of rows of a row major matrix or + * to set of columns of a column major matrix (optional). The parameter allows to determine + * at compile time whether aligned access is possible on the block expression. + * + * This class represents an expression of either a fixed-size or dynamic-size block. It is the return + * type of DenseBase::block(Index,Index,Index,Index) and DenseBase::block(Index,Index) and + * most of the time this is the only way it is used. + * + * However, if you want to directly maniputate block expressions, + * for instance if you want to write a function returning such an expression, you + * will need to use this class. + * + * Here is an example illustrating the dynamic case: + * \include class_Block.cpp + * Output: \verbinclude class_Block.out + * + * \note Even though this expression has dynamic size, in the case where \a XprType + * has fixed size, this expression inherits a fixed maximal size which means that evaluating + * it does not cause a dynamic memory allocation. + * + * Here is an example illustrating the fixed-size case: + * \include class_FixedBlock.cpp + * Output: \verbinclude class_FixedBlock.out + * + * \sa DenseBase::block(Index,Index,Index,Index), DenseBase::block(Index,Index), class VectorBlock + */ template class Block : public BlockImpl::StorageKind> { @@ -109,9 +109,12 @@ template class typedef Impl Base; EIGEN_GENERIC_PUBLIC_INTERFACE(Block) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Block) + + typedef typename internal::remove_all::type NestedExpression; /** Column or Row constructor */ + EIGEN_DEVICE_FUNC inline Block(XprType& xpr, Index i) : Impl(xpr,i) { eigen_assert( (i>=0) && ( @@ -121,25 +124,27 @@ template class /** Fixed-size constructor */ - inline Block(XprType& xpr, Index a_startRow, Index a_startCol) - : Impl(xpr, a_startRow, a_startCol) + EIGEN_DEVICE_FUNC + inline Block(XprType& xpr, Index startRow, Index startCol) + : Impl(xpr, startRow, startCol) { EIGEN_STATIC_ASSERT(RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic,THIS_METHOD_IS_ONLY_FOR_FIXED_SIZE) - eigen_assert(a_startRow >= 0 && BlockRows >= 1 && a_startRow + BlockRows <= xpr.rows() - && a_startCol >= 0 && BlockCols >= 1 && a_startCol + BlockCols <= xpr.cols()); + eigen_assert(startRow >= 0 && BlockRows >= 0 && startRow + BlockRows <= xpr.rows() + && startCol >= 0 && BlockCols >= 0 && startCol + BlockCols <= xpr.cols()); } /** Dynamic-size constructor */ + EIGEN_DEVICE_FUNC inline Block(XprType& xpr, - Index a_startRow, Index a_startCol, + Index startRow, Index startCol, Index blockRows, Index blockCols) - : Impl(xpr, a_startRow, a_startCol, blockRows, blockCols) + : Impl(xpr, startRow, startCol, blockRows, blockCols) { eigen_assert((RowsAtCompileTime==Dynamic || RowsAtCompileTime==blockRows) && (ColsAtCompileTime==Dynamic || ColsAtCompileTime==blockCols)); - eigen_assert(a_startRow >= 0 && blockRows >= 0 && a_startRow <= xpr.rows() - blockRows - && a_startCol >= 0 && blockCols >= 0 && a_startCol <= xpr.cols() - blockCols); + eigen_assert(startRow >= 0 && blockRows >= 0 && startRow <= xpr.rows() - blockRows + && startCol >= 0 && blockCols >= 0 && startCol <= xpr.cols() - blockCols); } }; @@ -150,14 +155,15 @@ class BlockImpl : public internal::BlockImpl_dense { typedef internal::BlockImpl_dense Impl; - typedef typename XprType::Index Index; + typedef typename XprType::StorageIndex StorageIndex; public: typedef Impl Base; EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl) - inline BlockImpl(XprType& xpr, Index i) : Impl(xpr,i) {} - inline BlockImpl(XprType& xpr, Index a_startRow, Index a_startCol) : Impl(xpr, a_startRow, a_startCol) {} - inline BlockImpl(XprType& xpr, Index a_startRow, Index a_startCol, Index blockRows, Index blockCols) - : Impl(xpr, a_startRow, a_startCol, blockRows, blockCols) {} + EIGEN_DEVICE_FUNC inline BlockImpl(XprType& xpr, Index i) : Impl(xpr,i) {} + EIGEN_DEVICE_FUNC inline BlockImpl(XprType& xpr, Index startRow, Index startCol) : Impl(xpr, startRow, startCol) {} + EIGEN_DEVICE_FUNC + inline BlockImpl(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) + : Impl(xpr, startRow, startCol, blockRows, blockCols) {} }; namespace internal { @@ -167,16 +173,18 @@ template >::type { typedef Block BlockType; + typedef typename internal::ref_selector::non_const_type XprTypeNested; public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(BlockType) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl_dense) - class InnerIterator; + // class InnerIterator; // FIXME apparently never used /** Column or Row constructor */ + EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index i) : m_xpr(xpr), // It is a row if and only if BlockRows==1 and BlockCols==XprType::ColsAtCompileTime, @@ -191,75 +199,76 @@ template inline PacketScalar packet(Index rowId, Index colId) const { - return m_xpr.template packet - (rowId + m_startRow.value(), colId + m_startCol.value()); + return m_xpr.template packet(rowId + m_startRow.value(), colId + m_startCol.value()); } template inline void writePacket(Index rowId, Index colId, const PacketScalar& val) { - m_xpr.const_cast_derived().template writePacket - (rowId + m_startRow.value(), colId + m_startCol.value(), val); + m_xpr.template writePacket(rowId + m_startRow.value(), colId + m_startCol.value(), val); } template @@ -273,40 +282,46 @@ template inline void writePacket(Index index, const PacketScalar& val) { - m_xpr.const_cast_derived().template writePacket + m_xpr.template writePacket (m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0), val); } #ifdef EIGEN_PARSED_BY_DOXYGEN /** \sa MapBase::data() */ - inline const Scalar* data() const; - inline Index innerStride() const; - inline Index outerStride() const; + EIGEN_DEVICE_FUNC inline const Scalar* data() const; + EIGEN_DEVICE_FUNC inline Index innerStride() const; + EIGEN_DEVICE_FUNC inline Index outerStride() const; #endif - const typename internal::remove_all::type& nestedExpression() const + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& nestedExpression() const { return m_xpr; } + + EIGEN_DEVICE_FUNC + XprType& nestedExpression() { return m_xpr; } - Index startRow() const + EIGEN_DEVICE_FUNC + StorageIndex startRow() const { return m_startRow.value(); } - Index startCol() const + EIGEN_DEVICE_FUNC + StorageIndex startCol() const { return m_startCol.value(); } protected: - const typename XprType::Nested m_xpr; - const internal::variable_if_dynamic m_startRow; - const internal::variable_if_dynamic m_startCol; - const internal::variable_if_dynamic m_blockRows; - const internal::variable_if_dynamic m_blockCols; + XprTypeNested m_xpr; + const internal::variable_if_dynamic m_startRow; + const internal::variable_if_dynamic m_startCol; + const internal::variable_if_dynamic m_blockRows; + const internal::variable_if_dynamic m_blockCols; }; /** \internal Internal implementation of dense Blocks in the direct access case.*/ @@ -315,6 +330,10 @@ class BlockImpl_dense : public MapBase > { typedef Block BlockType; + typedef typename internal::ref_selector::non_const_type XprTypeNested; + enum { + XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0 + }; public: typedef MapBase Base; @@ -323,42 +342,52 @@ class BlockImpl_dense /** Column or Row constructor */ + EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index i) - : Base(internal::const_cast_ptr(&xpr.coeffRef( - (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0, - (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0)), + : Base(xpr.data() + i * ( ((BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) && (!XprTypeIsRowMajor)) + || ((BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) && ( XprTypeIsRowMajor)) ? xpr.innerStride() : xpr.outerStride()), BlockRows==1 ? 1 : xpr.rows(), BlockCols==1 ? 1 : xpr.cols()), - m_xpr(xpr) + m_xpr(xpr), + m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0), + m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0) { init(); } /** Fixed-size constructor */ + EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol) - : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol))), m_xpr(xpr) + : Base(xpr.data()+xpr.innerStride()*(XprTypeIsRowMajor?startCol:startRow) + xpr.outerStride()*(XprTypeIsRowMajor?startRow:startCol)), + m_xpr(xpr), m_startRow(startRow), m_startCol(startCol) { init(); } /** Dynamic-size constructor */ + EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) - : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol)), blockRows, blockCols), - m_xpr(xpr) + : Base(xpr.data()+xpr.innerStride()*(XprTypeIsRowMajor?startCol:startRow) + xpr.outerStride()*(XprTypeIsRowMajor?startRow:startCol), blockRows, blockCols), + m_xpr(xpr), m_startRow(startRow), m_startCol(startCol) { init(); } - const typename internal::remove_all::type& nestedExpression() const + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& nestedExpression() const { return m_xpr; } + + EIGEN_DEVICE_FUNC + XprType& nestedExpression() { return m_xpr; } /** \sa MapBase::innerStride() */ + EIGEN_DEVICE_FUNC inline Index innerStride() const { return internal::traits::HasSameStorageOrderAsXprType @@ -367,11 +396,24 @@ class BlockImpl_dense } /** \sa MapBase::outerStride() */ + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_outerStride; } + EIGEN_DEVICE_FUNC + StorageIndex startRow() const + { + return m_startRow.value(); + } + + EIGEN_DEVICE_FUNC + StorageIndex startCol() const + { + return m_startCol.value(); + } + #ifndef __SUNPRO_CC // FIXME sunstudio is not friendly with the above friend... // META-FIXME there is no 'friend' keyword around here. Is this obsolete? @@ -380,6 +422,7 @@ class BlockImpl_dense #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal used by allowAligned() */ + EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, const Scalar* data, Index blockRows, Index blockCols) : Base(data, blockRows, blockCols), m_xpr(xpr) { @@ -388,6 +431,7 @@ class BlockImpl_dense #endif protected: + EIGEN_DEVICE_FUNC void init() { m_outerStride = internal::traits::HasSameStorageOrderAsXprType @@ -395,7 +439,9 @@ class BlockImpl_dense : m_xpr.innerStride(); } - typename XprType::Nested m_xpr; + XprTypeNested m_xpr; + const internal::variable_if_dynamic m_startRow; + const internal::variable_if_dynamic m_startCol; Index m_outerStride; }; diff --git a/splinter/src/Core/BooleanRedux.h b/splinter/thirdparty/Eigen/Eigen/src/Core/BooleanRedux.h similarity index 69% rename from splinter/src/Core/BooleanRedux.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/BooleanRedux.h index be9f48a8c7..8409d8749a 100644 --- a/splinter/src/Core/BooleanRedux.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/BooleanRedux.h @@ -17,9 +17,10 @@ namespace internal { template struct all_unroller { + typedef typename Derived::ExpressionTraits Traits; enum { - col = (UnrollCount-1) / Derived::RowsAtCompileTime, - row = (UnrollCount-1) % Derived::RowsAtCompileTime + col = (UnrollCount-1) / Traits::RowsAtCompileTime, + row = (UnrollCount-1) % Traits::RowsAtCompileTime }; static inline bool run(const Derived &mat) @@ -43,11 +44,12 @@ struct all_unroller template struct any_unroller { + typedef typename Derived::ExpressionTraits Traits; enum { - col = (UnrollCount-1) / Derived::RowsAtCompileTime, - row = (UnrollCount-1) % Derived::RowsAtCompileTime + col = (UnrollCount-1) / Traits::RowsAtCompileTime, + row = (UnrollCount-1) % Traits::RowsAtCompileTime }; - + static inline bool run(const Derived &mat) { return any_unroller::run(mat) || mat.coeff(row, col); @@ -78,19 +80,19 @@ struct any_unroller template inline bool DenseBase::all() const { + typedef internal::evaluator Evaluator; enum { unroll = SizeAtCompileTime != Dynamic - && CoeffReadCost != Dynamic - && NumTraits::AddCost != Dynamic - && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT + && SizeAtCompileTime * (Evaluator::CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT }; + Evaluator evaluator(derived()); if(unroll) - return internal::all_unroller::run(derived()); + return internal::all_unroller::run(evaluator); else { for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) - if (!coeff(i, j)) return false; + if (!evaluator.coeff(i, j)) return false; return true; } } @@ -102,19 +104,19 @@ inline bool DenseBase::all() const template inline bool DenseBase::any() const { + typedef internal::evaluator Evaluator; enum { unroll = SizeAtCompileTime != Dynamic - && CoeffReadCost != Dynamic - && NumTraits::AddCost != Dynamic - && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT + && SizeAtCompileTime * (Evaluator::CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT }; + Evaluator evaluator(derived()); if(unroll) - return internal::any_unroller::run(derived()); + return internal::any_unroller::run(evaluator); else { for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) - if (coeff(i, j)) return true; + if (evaluator.coeff(i, j)) return true; return false; } } @@ -124,7 +126,7 @@ inline bool DenseBase::any() const * \sa all(), any() */ template -inline typename DenseBase::Index DenseBase::count() const +inline Eigen::Index DenseBase::count() const { return derived().template cast().template cast().sum(); } @@ -136,7 +138,11 @@ inline typename DenseBase::Index DenseBase::count() const template inline bool DenseBase::hasNaN() const { +#if EIGEN_COMP_MSVC || (defined __FAST_MATH__) + return derived().array().isNaN().any(); +#else return !((derived().array()==derived().array()).all()); +#endif } /** \returns true if \c *this contains only finite numbers, i.e., no NaN and no +/-INF values. @@ -146,7 +152,11 @@ inline bool DenseBase::hasNaN() const template inline bool DenseBase::allFinite() const { +#if EIGEN_COMP_MSVC || (defined __FAST_MATH__) + return derived().array().isFinite().all(); +#else return !((derived()-derived()).hasNaN()); +#endif } } // end namespace Eigen diff --git a/splinter/src/Core/CommaInitializer.h b/splinter/thirdparty/Eigen/Eigen/src/Core/CommaInitializer.h similarity index 81% rename from splinter/src/Core/CommaInitializer.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/CommaInitializer.h index a036d8c3bc..d218e98143 100644 --- a/splinter/src/Core/CommaInitializer.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/CommaInitializer.h @@ -22,14 +22,14 @@ namespace Eigen { * the return type of MatrixBase::operator<<, and most of the time this is the only * way it is used. * - * \sa \ref MatrixBaseCommaInitRef "MatrixBase::operator<<", CommaInitializer::finished() + * \sa \blank \ref MatrixBaseCommaInitRef "MatrixBase::operator<<", CommaInitializer::finished() */ template struct CommaInitializer { typedef typename XprType::Scalar Scalar; - typedef typename XprType::Index Index; + EIGEN_DEVICE_FUNC inline CommaInitializer(XprType& xpr, const Scalar& s) : m_xpr(xpr), m_row(0), m_col(1), m_currentBlockRows(1) { @@ -37,6 +37,7 @@ struct CommaInitializer } template + EIGEN_DEVICE_FUNC inline CommaInitializer(XprType& xpr, const DenseBase& other) : m_xpr(xpr), m_row(0), m_col(other.cols()), m_currentBlockRows(other.rows()) { @@ -46,6 +47,7 @@ struct CommaInitializer /* Copy/Move constructor which transfers ownership. This is crucial in * absence of return value optimization to avoid assertions during destruction. */ // FIXME in C++11 mode this could be replaced by a proper RValue constructor + EIGEN_DEVICE_FUNC inline CommaInitializer(const CommaInitializer& o) : m_xpr(o.m_xpr), m_row(o.m_row), m_col(o.m_col), m_currentBlockRows(o.m_currentBlockRows) { // Mark original object as finished. In absence of R-value references we need to const_cast: @@ -55,6 +57,7 @@ struct CommaInitializer } /* inserts a scalar value in the target matrix */ + EIGEN_DEVICE_FUNC CommaInitializer& operator,(const Scalar& s) { if (m_col==m_xpr.cols()) @@ -74,11 +77,10 @@ struct CommaInitializer /* inserts a matrix expression in the target matrix */ template + EIGEN_DEVICE_FUNC CommaInitializer& operator,(const DenseBase& other) { - if(other.cols()==0 || other.rows()==0) - return *this; - if (m_col==m_xpr.cols()) + if (m_col==m_xpr.cols() && (other.cols()!=0 || other.rows()!=m_currentBlockRows)) { m_row+=m_currentBlockRows; m_col = 0; @@ -86,24 +88,22 @@ struct CommaInitializer eigen_assert(m_row+m_currentBlockRows<=m_xpr.rows() && "Too many rows passed to comma initializer (operator<<)"); } - eigen_assert(m_col - (m_row, m_col) = other; - else - m_xpr.block(m_row, m_col, other.rows(), other.cols()) = other; + m_xpr.template block + (m_row, m_col, other.rows(), other.cols()) = other; m_col += other.cols(); return *this; } + EIGEN_DEVICE_FUNC inline ~CommaInitializer() +#if defined VERIFY_RAISES_ASSERT && (!defined EIGEN_NO_ASSERTION_CHECKING) && defined EIGEN_EXCEPTIONS + EIGEN_EXCEPTION_SPEC(Eigen::eigen_assert_exception) +#endif { - eigen_assert((m_row+m_currentBlockRows) == m_xpr.rows() - && m_col == m_xpr.cols() - && "Too few coefficients passed to comma initializer (operator<<)"); + finished(); } /** \returns the built matrix once all its coefficients have been set. @@ -113,9 +113,15 @@ struct CommaInitializer * quaternion.fromRotationMatrix((Matrix3f() << axis0, axis1, axis2).finished()); * \endcode */ - inline XprType& finished() { return m_xpr; } + EIGEN_DEVICE_FUNC + inline XprType& finished() { + eigen_assert(((m_row+m_currentBlockRows) == m_xpr.rows() || m_xpr.cols() == 0) + && m_col == m_xpr.cols() + && "Too few coefficients passed to comma initializer (operator<<)"); + return m_xpr; + } - XprType& m_xpr; // target expression + XprType& m_xpr; // target expression Index m_row; // current row id Index m_col; // current col id Index m_currentBlockRows; // current block height diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/ConditionEstimator.h b/splinter/thirdparty/Eigen/Eigen/src/Core/ConditionEstimator.h new file mode 100644 index 0000000000..aa7efdc765 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/ConditionEstimator.h @@ -0,0 +1,175 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2016 Rasmus Munk Larsen (rmlarsen@google.com) +// +// 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_CONDITIONESTIMATOR_H +#define EIGEN_CONDITIONESTIMATOR_H + +namespace Eigen { + +namespace internal { + +template +struct rcond_compute_sign { + static inline Vector run(const Vector& v) { + const RealVector v_abs = v.cwiseAbs(); + return (v_abs.array() == static_cast(0)) + .select(Vector::Ones(v.size()), v.cwiseQuotient(v_abs)); + } +}; + +// Partial specialization to avoid elementwise division for real vectors. +template +struct rcond_compute_sign { + static inline Vector run(const Vector& v) { + return (v.array() < static_cast(0)) + .select(-Vector::Ones(v.size()), Vector::Ones(v.size())); + } +}; + +/** + * \returns an estimate of ||inv(matrix)||_1 given a decomposition of + * \a matrix that implements .solve() and .adjoint().solve() methods. + * + * This function implements Algorithms 4.1 and 5.1 from + * http://www.maths.manchester.ac.uk/~higham/narep/narep135.pdf + * which also forms the basis for the condition number estimators in + * LAPACK. Since at most 10 calls to the solve method of dec are + * performed, the total cost is O(dims^2), as opposed to O(dims^3) + * needed to compute the inverse matrix explicitly. + * + * The most common usage is in estimating the condition number + * ||matrix||_1 * ||inv(matrix)||_1. The first term ||matrix||_1 can be + * computed directly in O(n^2) operations. + * + * Supports the following decompositions: FullPivLU, PartialPivLU, LDLT, and + * LLT. + * + * \sa FullPivLU, PartialPivLU, LDLT, LLT. + */ +template +typename Decomposition::RealScalar rcond_invmatrix_L1_norm_estimate(const Decomposition& dec) +{ + typedef typename Decomposition::MatrixType MatrixType; + typedef typename Decomposition::Scalar Scalar; + typedef typename Decomposition::RealScalar RealScalar; + typedef typename internal::plain_col_type::type Vector; + typedef typename internal::plain_col_type::type RealVector; + const bool is_complex = (NumTraits::IsComplex != 0); + + eigen_assert(dec.rows() == dec.cols()); + const Index n = dec.rows(); + if (n == 0) + return 0; + + // Disable Index to float conversion warning +#ifdef __INTEL_COMPILER + #pragma warning push + #pragma warning ( disable : 2259 ) +#endif + Vector v = dec.solve(Vector::Ones(n) / Scalar(n)); +#ifdef __INTEL_COMPILER + #pragma warning pop +#endif + + // lower_bound is a lower bound on + // ||inv(matrix)||_1 = sup_v ||inv(matrix) v||_1 / ||v||_1 + // and is the objective maximized by the ("super-") gradient ascent + // algorithm below. + RealScalar lower_bound = v.template lpNorm<1>(); + if (n == 1) + return lower_bound; + + // Gradient ascent algorithm follows: We know that the optimum is achieved at + // one of the simplices v = e_i, so in each iteration we follow a + // super-gradient to move towards the optimal one. + RealScalar old_lower_bound = lower_bound; + Vector sign_vector(n); + Vector old_sign_vector; + Index v_max_abs_index = -1; + Index old_v_max_abs_index = v_max_abs_index; + for (int k = 0; k < 4; ++k) + { + sign_vector = internal::rcond_compute_sign::run(v); + if (k > 0 && !is_complex && sign_vector == old_sign_vector) { + // Break if the solution stagnated. + break; + } + // v_max_abs_index = argmax |real( inv(matrix)^T * sign_vector )| + v = dec.adjoint().solve(sign_vector); + v.real().cwiseAbs().maxCoeff(&v_max_abs_index); + if (v_max_abs_index == old_v_max_abs_index) { + // Break if the solution stagnated. + break; + } + // Move to the new simplex e_j, where j = v_max_abs_index. + v = dec.solve(Vector::Unit(n, v_max_abs_index)); // v = inv(matrix) * e_j. + lower_bound = v.template lpNorm<1>(); + if (lower_bound <= old_lower_bound) { + // Break if the gradient step did not increase the lower_bound. + break; + } + if (!is_complex) { + old_sign_vector = sign_vector; + } + old_v_max_abs_index = v_max_abs_index; + old_lower_bound = lower_bound; + } + // The following calculates an independent estimate of ||matrix||_1 by + // multiplying matrix by a vector with entries of slowly increasing + // magnitude and alternating sign: + // v_i = (-1)^{i} (1 + (i / (dim-1))), i = 0,...,dim-1. + // This improvement to Hager's algorithm above is due to Higham. It was + // added to make the algorithm more robust in certain corner cases where + // large elements in the matrix might otherwise escape detection due to + // exact cancellation (especially when op and op_adjoint correspond to a + // sequence of backsubstitutions and permutations), which could cause + // Hager's algorithm to vastly underestimate ||matrix||_1. + Scalar alternating_sign(RealScalar(1)); + for (Index i = 0; i < n; ++i) { + // The static_cast is needed when Scalar is a complex and RealScalar implements expression templates + v[i] = alternating_sign * static_cast(RealScalar(1) + (RealScalar(i) / (RealScalar(n - 1)))); + alternating_sign = -alternating_sign; + } + v = dec.solve(v); + const RealScalar alternate_lower_bound = (2 * v.template lpNorm<1>()) / (3 * RealScalar(n)); + return numext::maxi(lower_bound, alternate_lower_bound); +} + +/** \brief Reciprocal condition number estimator. + * + * Computing a decomposition of a dense matrix takes O(n^3) operations, while + * this method estimates the condition number quickly and reliably in O(n^2) + * operations. + * + * \returns an estimate of the reciprocal condition number + * (1 / (||matrix||_1 * ||inv(matrix)||_1)) of matrix, given ||matrix||_1 and + * its decomposition. Supports the following decompositions: FullPivLU, + * PartialPivLU, LDLT, and LLT. + * + * \sa FullPivLU, PartialPivLU, LDLT, LLT. + */ +template +typename Decomposition::RealScalar +rcond_estimate_helper(typename Decomposition::RealScalar matrix_norm, const Decomposition& dec) +{ + typedef typename Decomposition::RealScalar RealScalar; + eigen_assert(dec.rows() == dec.cols()); + if (dec.rows() == 0) return RealScalar(1); + if (matrix_norm == RealScalar(0)) return RealScalar(0); + if (dec.rows() == 1) return RealScalar(1); + const RealScalar inverse_matrix_norm = rcond_invmatrix_L1_norm_estimate(dec); + return (inverse_matrix_norm == RealScalar(0) ? RealScalar(0) + : (RealScalar(1) / inverse_matrix_norm) / matrix_norm); +} + +} // namespace internal + +} // namespace Eigen + +#endif diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/CoreEvaluators.h b/splinter/thirdparty/Eigen/Eigen/src/Core/CoreEvaluators.h new file mode 100644 index 0000000000..910889efa7 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/CoreEvaluators.h @@ -0,0 +1,1688 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Benoit Jacob +// Copyright (C) 2011-2014 Gael Guennebaud +// Copyright (C) 2011-2012 Jitse Niesen +// +// 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_COREEVALUATORS_H +#define EIGEN_COREEVALUATORS_H + +namespace Eigen { + +namespace internal { + +// This class returns the evaluator kind from the expression storage kind. +// Default assumes index based accessors +template +struct storage_kind_to_evaluator_kind { + typedef IndexBased Kind; +}; + +// This class returns the evaluator shape from the expression storage kind. +// It can be Dense, Sparse, Triangular, Diagonal, SelfAdjoint, Band, etc. +template struct storage_kind_to_shape; + +template<> struct storage_kind_to_shape { typedef DenseShape Shape; }; +template<> struct storage_kind_to_shape { typedef SolverShape Shape; }; +template<> struct storage_kind_to_shape { typedef PermutationShape Shape; }; +template<> struct storage_kind_to_shape { typedef TranspositionsShape Shape; }; + +// Evaluators have to be specialized with respect to various criteria such as: +// - storage/structure/shape +// - scalar type +// - etc. +// Therefore, we need specialization of evaluator providing additional template arguments for each kind of evaluators. +// We currently distinguish the following kind of evaluators: +// - unary_evaluator for expressions taking only one arguments (CwiseUnaryOp, CwiseUnaryView, Transpose, MatrixWrapper, ArrayWrapper, Reverse, Replicate) +// - binary_evaluator for expression taking two arguments (CwiseBinaryOp) +// - ternary_evaluator for expression taking three arguments (CwiseTernaryOp) +// - product_evaluator for linear algebra products (Product); special case of binary_evaluator because it requires additional tags for dispatching. +// - mapbase_evaluator for Map, Block, Ref +// - block_evaluator for Block (special dispatching to a mapbase_evaluator or unary_evaluator) + +template< typename T, + typename Arg1Kind = typename evaluator_traits::Kind, + typename Arg2Kind = typename evaluator_traits::Kind, + typename Arg3Kind = typename evaluator_traits::Kind, + typename Arg1Scalar = typename traits::Scalar, + typename Arg2Scalar = typename traits::Scalar, + typename Arg3Scalar = typename traits::Scalar> struct ternary_evaluator; + +template< typename T, + typename LhsKind = typename evaluator_traits::Kind, + typename RhsKind = typename evaluator_traits::Kind, + typename LhsScalar = typename traits::Scalar, + typename RhsScalar = typename traits::Scalar> struct binary_evaluator; + +template< typename T, + typename Kind = typename evaluator_traits::Kind, + typename Scalar = typename T::Scalar> struct unary_evaluator; + +// evaluator_traits contains traits for evaluator + +template +struct evaluator_traits_base +{ + // by default, get evaluator kind and shape from storage + typedef typename storage_kind_to_evaluator_kind::StorageKind>::Kind Kind; + typedef typename storage_kind_to_shape::StorageKind>::Shape Shape; +}; + +// Default evaluator traits +template +struct evaluator_traits : public evaluator_traits_base +{ +}; + +template::Shape > +struct evaluator_assume_aliasing { + static const bool value = false; +}; + +// By default, we assume a unary expression: +template +struct evaluator : public unary_evaluator +{ + typedef unary_evaluator Base; + EIGEN_DEVICE_FUNC explicit evaluator(const T& xpr) : Base(xpr) {} +}; + + +// TODO: Think about const-correctness +template +struct evaluator + : evaluator +{ + EIGEN_DEVICE_FUNC + explicit evaluator(const T& xpr) : evaluator(xpr) {} +}; + +// ---------- base class for all evaluators ---------- + +template +struct evaluator_base : public noncopyable +{ + // TODO that's not very nice to have to propagate all these traits. They are currently only needed to handle outer,inner indices. + typedef traits ExpressionTraits; + + enum { + Alignment = 0 + }; +}; + +// -------------------- Matrix and Array -------------------- +// +// evaluator is a common base class for the +// Matrix and Array evaluators. +// Here we directly specialize evaluator. This is not really a unary expression, and it is, by definition, dense, +// so no need for more sophisticated dispatching. + +template +struct evaluator > + : evaluator_base +{ + typedef PlainObjectBase PlainObjectType; + typedef typename PlainObjectType::Scalar Scalar; + typedef typename PlainObjectType::CoeffReturnType CoeffReturnType; + + enum { + IsRowMajor = PlainObjectType::IsRowMajor, + IsVectorAtCompileTime = PlainObjectType::IsVectorAtCompileTime, + RowsAtCompileTime = PlainObjectType::RowsAtCompileTime, + ColsAtCompileTime = PlainObjectType::ColsAtCompileTime, + + CoeffReadCost = NumTraits::ReadCost, + Flags = traits::EvaluatorFlags, + Alignment = traits::Alignment + }; + + EIGEN_DEVICE_FUNC evaluator() + : m_data(0), + m_outerStride(IsVectorAtCompileTime ? 0 + : int(IsRowMajor) ? ColsAtCompileTime + : RowsAtCompileTime) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + EIGEN_DEVICE_FUNC explicit evaluator(const PlainObjectType& m) + : m_data(m.data()), m_outerStride(IsVectorAtCompileTime ? 0 : m.outerStride()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + if (IsRowMajor) + return m_data[row * m_outerStride.value() + col]; + else + return m_data[row + col * m_outerStride.value()]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_data[index]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + if (IsRowMajor) + return const_cast(m_data)[row * m_outerStride.value() + col]; + else + return const_cast(m_data)[row + col * m_outerStride.value()]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return const_cast(m_data)[index]; + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + if (IsRowMajor) + return ploadt(m_data + row * m_outerStride.value() + col); + else + return ploadt(m_data + row + col * m_outerStride.value()); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return ploadt(m_data + index); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + if (IsRowMajor) + return pstoret + (const_cast(m_data) + row * m_outerStride.value() + col, x); + else + return pstoret + (const_cast(m_data) + row + col * m_outerStride.value(), x); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + return pstoret(const_cast(m_data) + index, x); + } + +protected: + const Scalar *m_data; + + // We do not need to know the outer stride for vectors + variable_if_dynamic m_outerStride; +}; + +template +struct evaluator > + : evaluator > > +{ + typedef Matrix XprType; + + EIGEN_DEVICE_FUNC evaluator() {} + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& m) + : evaluator >(m) + { } +}; + +template +struct evaluator > + : evaluator > > +{ + typedef Array XprType; + + EIGEN_DEVICE_FUNC evaluator() {} + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& m) + : evaluator >(m) + { } +}; + +// -------------------- Transpose -------------------- + +template +struct unary_evaluator, IndexBased> + : evaluator_base > +{ + typedef Transpose XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = evaluator::Flags ^ RowMajorBit, + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& t) : m_argImpl(t.nestedExpression()) {} + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(col, row); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_argImpl.coeff(index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(col, row); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + typename XprType::Scalar& coeffRef(Index index) + { + return m_argImpl.coeffRef(index); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_argImpl.template packet(col, row); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return m_argImpl.template packet(index); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + m_argImpl.template writePacket(col, row, x); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + m_argImpl.template writePacket(index, x); + } + +protected: + evaluator m_argImpl; +}; + +// -------------------- CwiseNullaryOp -------------------- +// Like Matrix and Array, this is not really a unary expression, so we directly specialize evaluator. +// Likewise, there is not need to more sophisticated dispatching here. + +template::value, + bool has_unary = has_unary_operator::value, + bool has_binary = has_binary_operator::value> +struct nullary_wrapper +{ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j) const { return op(i,j); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const { return op(i); } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const { return op.template packetOp(i,j); } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const { return op.template packetOp(i); } +}; + +template +struct nullary_wrapper +{ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType=0, IndexType=0) const { return op(); } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType=0, IndexType=0) const { return op.template packetOp(); } +}; + +template +struct nullary_wrapper +{ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j=0) const { return op(i,j); } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j=0) const { return op.template packetOp(i,j); } +}; + +// We need the following specialization for vector-only functors assigned to a runtime vector, +// for instance, using linspace and assigning a RowVectorXd to a MatrixXd or even a row of a MatrixXd. +// In this case, i==0 and j is used for the actual iteration. +template +struct nullary_wrapper +{ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j) const { + eigen_assert(i==0 || j==0); + return op(i+j); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const { + eigen_assert(i==0 || j==0); + return op.template packetOp(i+j); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const { return op(i); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const { return op.template packetOp(i); } +}; + +template +struct nullary_wrapper {}; + +#if 0 && EIGEN_COMP_MSVC>0 +// Disable this ugly workaround. This is now handled in traits::match, +// but this piece of code might still become handly if some other weird compilation +// erros pop up again. + +// MSVC exhibits a weird compilation error when +// compiling: +// Eigen::MatrixXf A = MatrixXf::Random(3,3); +// Ref R = 2.f*A; +// and that has_*ary_operator> have not been instantiated yet. +// The "problem" is that evaluator<2.f*A> is instantiated by traits::match<2.f*A> +// and at that time has_*ary_operator returns true regardless of T. +// Then nullary_wrapper is badly instantiated as nullary_wrapper<.,.,true,true,true>. +// The trick is thus to defer the proper instantiation of nullary_wrapper when coeff(), +// and packet() are really instantiated as implemented below: + +// This is a simple wrapper around Index to enforce the re-instantiation of +// has_*ary_operator when needed. +template struct nullary_wrapper_workaround_msvc { + nullary_wrapper_workaround_msvc(const T&); + operator T()const; +}; + +template +struct nullary_wrapper +{ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j) const { + return nullary_wrapper >::value, + has_unary_operator >::value, + has_binary_operator >::value>().operator()(op,i,j); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const { + return nullary_wrapper >::value, + has_unary_operator >::value, + has_binary_operator >::value>().operator()(op,i); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const { + return nullary_wrapper >::value, + has_unary_operator >::value, + has_binary_operator >::value>().template packetOp(op,i,j); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const { + return nullary_wrapper >::value, + has_unary_operator >::value, + has_binary_operator >::value>().template packetOp(op,i); + } +}; +#endif // MSVC workaround + +template +struct evaluator > + : evaluator_base > +{ + typedef CwiseNullaryOp XprType; + typedef typename internal::remove_all::type PlainObjectTypeCleaned; + + enum { + CoeffReadCost = internal::functor_traits::Cost, + + Flags = (evaluator::Flags + & ( HereditaryBits + | (functor_has_linear_access::ret ? LinearAccessBit : 0) + | (functor_traits::PacketAccess ? PacketAccessBit : 0))) + | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit), + Alignment = AlignedMax + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& n) + : m_functor(n.functor()), m_wrapper() + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(IndexType row, IndexType col) const + { + return m_wrapper(m_functor, row, col); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(IndexType index) const + { + return m_wrapper(m_functor,index); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(IndexType row, IndexType col) const + { + return m_wrapper.template packetOp(m_functor, row, col); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(IndexType index) const + { + return m_wrapper.template packetOp(m_functor, index); + } + +protected: + const NullaryOp m_functor; + const internal::nullary_wrapper m_wrapper; +}; + +// -------------------- CwiseUnaryOp -------------------- + +template +struct unary_evaluator, IndexBased > + : evaluator_base > +{ + typedef CwiseUnaryOp XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost, + + Flags = evaluator::Flags + & (HereditaryBits | LinearAccessBit | (functor_traits::PacketAccess ? PacketAccessBit : 0)), + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit unary_evaluator(const XprType& op) + : m_functor(op.functor()), + m_argImpl(op.nestedExpression()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_functor(m_argImpl.coeff(row, col)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_functor(m_argImpl.coeff(index)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_functor.packetOp(m_argImpl.template packet(row, col)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return m_functor.packetOp(m_argImpl.template packet(index)); + } + +protected: + const UnaryOp m_functor; + evaluator m_argImpl; +}; + +// -------------------- CwiseTernaryOp -------------------- + +// this is a ternary expression +template +struct evaluator > + : public ternary_evaluator > +{ + typedef CwiseTernaryOp XprType; + typedef ternary_evaluator > Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(xpr) {} +}; + +template +struct ternary_evaluator, IndexBased, IndexBased> + : evaluator_base > +{ + typedef CwiseTernaryOp XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, + + Arg1Flags = evaluator::Flags, + Arg2Flags = evaluator::Flags, + Arg3Flags = evaluator::Flags, + SameType = is_same::value && is_same::value, + StorageOrdersAgree = (int(Arg1Flags)&RowMajorBit)==(int(Arg2Flags)&RowMajorBit) && (int(Arg1Flags)&RowMajorBit)==(int(Arg3Flags)&RowMajorBit), + Flags0 = (int(Arg1Flags) | int(Arg2Flags) | int(Arg3Flags)) & ( + HereditaryBits + | (int(Arg1Flags) & int(Arg2Flags) & int(Arg3Flags) & + ( (StorageOrdersAgree ? LinearAccessBit : 0) + | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) + ) + ) + ), + Flags = (Flags0 & ~RowMajorBit) | (Arg1Flags & RowMajorBit), + Alignment = EIGEN_PLAIN_ENUM_MIN( + EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment, evaluator::Alignment), + evaluator::Alignment) + }; + + EIGEN_DEVICE_FUNC explicit ternary_evaluator(const XprType& xpr) + : m_functor(xpr.functor()), + m_arg1Impl(xpr.arg1()), + m_arg2Impl(xpr.arg2()), + m_arg3Impl(xpr.arg3()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_functor(m_arg1Impl.coeff(row, col), m_arg2Impl.coeff(row, col), m_arg3Impl.coeff(row, col)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_functor(m_arg1Impl.coeff(index), m_arg2Impl.coeff(index), m_arg3Impl.coeff(index)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_functor.packetOp(m_arg1Impl.template packet(row, col), + m_arg2Impl.template packet(row, col), + m_arg3Impl.template packet(row, col)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return m_functor.packetOp(m_arg1Impl.template packet(index), + m_arg2Impl.template packet(index), + m_arg3Impl.template packet(index)); + } + +protected: + const TernaryOp m_functor; + evaluator m_arg1Impl; + evaluator m_arg2Impl; + evaluator m_arg3Impl; +}; + +// -------------------- CwiseBinaryOp -------------------- + +// this is a binary expression +template +struct evaluator > + : public binary_evaluator > +{ + typedef CwiseBinaryOp XprType; + typedef binary_evaluator > Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(xpr) {} +}; + +template +struct binary_evaluator, IndexBased, IndexBased> + : evaluator_base > +{ + typedef CwiseBinaryOp XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, + + LhsFlags = evaluator::Flags, + RhsFlags = evaluator::Flags, + SameType = is_same::value, + StorageOrdersAgree = (int(LhsFlags)&RowMajorBit)==(int(RhsFlags)&RowMajorBit), + Flags0 = (int(LhsFlags) | int(RhsFlags)) & ( + HereditaryBits + | (int(LhsFlags) & int(RhsFlags) & + ( (StorageOrdersAgree ? LinearAccessBit : 0) + | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) + ) + ) + ), + Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit), + Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment,evaluator::Alignment) + }; + + EIGEN_DEVICE_FUNC explicit binary_evaluator(const XprType& xpr) + : m_functor(xpr.functor()), + m_lhsImpl(xpr.lhs()), + m_rhsImpl(xpr.rhs()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_functor(m_lhsImpl.coeff(row, col), m_rhsImpl.coeff(row, col)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_functor(m_lhsImpl.coeff(index), m_rhsImpl.coeff(index)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_functor.packetOp(m_lhsImpl.template packet(row, col), + m_rhsImpl.template packet(row, col)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return m_functor.packetOp(m_lhsImpl.template packet(index), + m_rhsImpl.template packet(index)); + } + +protected: + const BinaryOp m_functor; + evaluator m_lhsImpl; + evaluator m_rhsImpl; +}; + +// -------------------- CwiseUnaryView -------------------- + +template +struct unary_evaluator, IndexBased> + : evaluator_base > +{ + typedef CwiseUnaryView XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost, + + Flags = (evaluator::Flags & (HereditaryBits | LinearAccessBit | DirectAccessBit)), + + Alignment = 0 // FIXME it is not very clear why alignment is necessarily lost... + }; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& op) + : m_unaryOp(op.functor()), + m_argImpl(op.nestedExpression()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_unaryOp(m_argImpl.coeff(row, col)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_unaryOp(m_argImpl.coeff(index)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_unaryOp(m_argImpl.coeffRef(row, col)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return m_unaryOp(m_argImpl.coeffRef(index)); + } + +protected: + const UnaryOp m_unaryOp; + evaluator m_argImpl; +}; + +// -------------------- Map -------------------- + +// FIXME perhaps the PlainObjectType could be provided by Derived::PlainObject ? +// but that might complicate template specialization +template +struct mapbase_evaluator; + +template +struct mapbase_evaluator : evaluator_base +{ + typedef Derived XprType; + typedef typename XprType::PointerType PointerType; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + enum { + IsRowMajor = XprType::RowsAtCompileTime, + ColsAtCompileTime = XprType::ColsAtCompileTime, + CoeffReadCost = NumTraits::ReadCost + }; + + EIGEN_DEVICE_FUNC explicit mapbase_evaluator(const XprType& map) + : m_data(const_cast(map.data())), + m_innerStride(map.innerStride()), + m_outerStride(map.outerStride()) + { + EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(evaluator::Flags&PacketAccessBit, internal::inner_stride_at_compile_time::ret==1), + PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_data[col * colStride() + row * rowStride()]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_data[index * m_innerStride.value()]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_data[col * colStride() + row * rowStride()]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return m_data[index * m_innerStride.value()]; + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + PointerType ptr = m_data + row * rowStride() + col * colStride(); + return internal::ploadt(ptr); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return internal::ploadt(m_data + index * m_innerStride.value()); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + PointerType ptr = m_data + row * rowStride() + col * colStride(); + return internal::pstoret(ptr, x); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + internal::pstoret(m_data + index * m_innerStride.value(), x); + } +protected: + EIGEN_DEVICE_FUNC + inline Index rowStride() const { return XprType::IsRowMajor ? m_outerStride.value() : m_innerStride.value(); } + EIGEN_DEVICE_FUNC + inline Index colStride() const { return XprType::IsRowMajor ? m_innerStride.value() : m_outerStride.value(); } + + PointerType m_data; + const internal::variable_if_dynamic m_innerStride; + const internal::variable_if_dynamic m_outerStride; +}; + +template +struct evaluator > + : public mapbase_evaluator, PlainObjectType> +{ + typedef Map XprType; + typedef typename XprType::Scalar Scalar; + // TODO: should check for smaller packet types once we can handle multi-sized packet types + typedef typename packet_traits::type PacketScalar; + + enum { + InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 + ? int(PlainObjectType::InnerStrideAtCompileTime) + : int(StrideType::InnerStrideAtCompileTime), + OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 + ? int(PlainObjectType::OuterStrideAtCompileTime) + : int(StrideType::OuterStrideAtCompileTime), + HasNoInnerStride = InnerStrideAtCompileTime == 1, + HasNoOuterStride = StrideType::OuterStrideAtCompileTime == 0, + HasNoStride = HasNoInnerStride && HasNoOuterStride, + IsDynamicSize = PlainObjectType::SizeAtCompileTime==Dynamic, + + PacketAccessMask = bool(HasNoInnerStride) ? ~int(0) : ~int(PacketAccessBit), + LinearAccessMask = bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime) ? ~int(0) : ~int(LinearAccessBit), + Flags = int( evaluator::Flags) & (LinearAccessMask&PacketAccessMask), + + Alignment = int(MapOptions)&int(AlignedMask) + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& map) + : mapbase_evaluator(map) + { } +}; + +// -------------------- Ref -------------------- + +template +struct evaluator > + : public mapbase_evaluator, PlainObjectType> +{ + typedef Ref XprType; + + enum { + Flags = evaluator >::Flags, + Alignment = evaluator >::Alignment + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& ref) + : mapbase_evaluator(ref) + { } +}; + +// -------------------- Block -------------------- + +template::ret> struct block_evaluator; + +template +struct evaluator > + : block_evaluator +{ + typedef Block XprType; + typedef typename XprType::Scalar Scalar; + // TODO: should check for smaller packet types once we can handle multi-sized packet types + typedef typename packet_traits::type PacketScalar; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + + RowsAtCompileTime = traits::RowsAtCompileTime, + ColsAtCompileTime = traits::ColsAtCompileTime, + MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = traits::MaxColsAtCompileTime, + + ArgTypeIsRowMajor = (int(evaluator::Flags)&RowMajorBit) != 0, + IsRowMajor = (MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1) ? 0 + : ArgTypeIsRowMajor, + HasSameStorageOrderAsArgType = (IsRowMajor == ArgTypeIsRowMajor), + InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime), + InnerStrideAtCompileTime = HasSameStorageOrderAsArgType + ? int(inner_stride_at_compile_time::ret) + : int(outer_stride_at_compile_time::ret), + OuterStrideAtCompileTime = HasSameStorageOrderAsArgType + ? int(outer_stride_at_compile_time::ret) + : int(inner_stride_at_compile_time::ret), + MaskPacketAccessBit = (InnerStrideAtCompileTime == 1 || HasSameStorageOrderAsArgType) ? PacketAccessBit : 0, + + FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (evaluator::Flags&LinearAccessBit))) ? LinearAccessBit : 0, + FlagsRowMajorBit = XprType::Flags&RowMajorBit, + Flags0 = evaluator::Flags & ( (HereditaryBits & ~RowMajorBit) | + DirectAccessBit | + MaskPacketAccessBit), + Flags = Flags0 | FlagsLinearAccessBit | FlagsRowMajorBit, + + PacketAlignment = unpacket_traits::alignment, + Alignment0 = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) + && (OuterStrideAtCompileTime!=0) + && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % int(PacketAlignment)) == 0)) ? int(PacketAlignment) : 0, + Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment, Alignment0) + }; + typedef block_evaluator block_evaluator_type; + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& block) : block_evaluator_type(block) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } +}; + +// no direct-access => dispatch to a unary evaluator +template +struct block_evaluator + : unary_evaluator > +{ + typedef Block XprType; + + EIGEN_DEVICE_FUNC explicit block_evaluator(const XprType& block) + : unary_evaluator(block) + {} +}; + +template +struct unary_evaluator, IndexBased> + : evaluator_base > +{ + typedef Block XprType; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& block) + : m_argImpl(block.nestedExpression()), + m_startRow(block.startRow()), + m_startCol(block.startCol()), + m_linear_offset(InnerPanel?(XprType::IsRowMajor ? block.startRow()*block.cols() : block.startCol()*block.rows()):0) + { } + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + enum { + RowsAtCompileTime = XprType::RowsAtCompileTime, + ForwardLinearAccess = InnerPanel && bool(evaluator::Flags&LinearAccessBit) + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(m_startRow.value() + row, m_startCol.value() + col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + if (ForwardLinearAccess) + return m_argImpl.coeff(m_linear_offset.value() + index); + else + return coeff(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(m_startRow.value() + row, m_startCol.value() + col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + if (ForwardLinearAccess) + return m_argImpl.coeffRef(m_linear_offset.value() + index); + else + return coeffRef(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_argImpl.template packet(m_startRow.value() + row, m_startCol.value() + col); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + if (ForwardLinearAccess) + return m_argImpl.template packet(m_linear_offset.value() + index); + else + return packet(RowsAtCompileTime == 1 ? 0 : index, + RowsAtCompileTime == 1 ? index : 0); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + return m_argImpl.template writePacket(m_startRow.value() + row, m_startCol.value() + col, x); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + if (ForwardLinearAccess) + return m_argImpl.template writePacket(m_linear_offset.value() + index, x); + else + return writePacket(RowsAtCompileTime == 1 ? 0 : index, + RowsAtCompileTime == 1 ? index : 0, + x); + } + +protected: + evaluator m_argImpl; + const variable_if_dynamic m_startRow; + const variable_if_dynamic m_startCol; + const variable_if_dynamic m_linear_offset; +}; + +// TODO: This evaluator does not actually use the child evaluator; +// all action is via the data() as returned by the Block expression. + +template +struct block_evaluator + : mapbase_evaluator, + typename Block::PlainObject> +{ + typedef Block XprType; + typedef typename XprType::Scalar Scalar; + + EIGEN_DEVICE_FUNC explicit block_evaluator(const XprType& block) + : mapbase_evaluator(block) + { + // TODO: for the 3.3 release, this should be turned to an internal assertion, but let's keep it as is for the beta lifetime + eigen_assert(((internal::UIntPtr(block.data()) % EIGEN_PLAIN_ENUM_MAX(1,evaluator::Alignment)) == 0) && "data is not aligned"); + } +}; + + +// -------------------- Select -------------------- +// NOTE shall we introduce a ternary_evaluator? + +// TODO enable vectorization for Select +template +struct evaluator > + : evaluator_base > +{ + typedef Select XprType; + enum { + CoeffReadCost = evaluator::CoeffReadCost + + EIGEN_PLAIN_ENUM_MAX(evaluator::CoeffReadCost, + evaluator::CoeffReadCost), + + Flags = (unsigned int)evaluator::Flags & evaluator::Flags & HereditaryBits, + + Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment, evaluator::Alignment) + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& select) + : m_conditionImpl(select.conditionMatrix()), + m_thenImpl(select.thenMatrix()), + m_elseImpl(select.elseMatrix()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + if (m_conditionImpl.coeff(row, col)) + return m_thenImpl.coeff(row, col); + else + return m_elseImpl.coeff(row, col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + if (m_conditionImpl.coeff(index)) + return m_thenImpl.coeff(index); + else + return m_elseImpl.coeff(index); + } + +protected: + evaluator m_conditionImpl; + evaluator m_thenImpl; + evaluator m_elseImpl; +}; + + +// -------------------- Replicate -------------------- + +template +struct unary_evaluator > + : evaluator_base > +{ + typedef Replicate XprType; + typedef typename XprType::CoeffReturnType CoeffReturnType; + enum { + Factor = (RowFactor==Dynamic || ColFactor==Dynamic) ? Dynamic : RowFactor*ColFactor + }; + typedef typename internal::nested_eval::type ArgTypeNested; + typedef typename internal::remove_all::type ArgTypeNestedCleaned; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + LinearAccessMask = XprType::IsVectorAtCompileTime ? LinearAccessBit : 0, + Flags = (evaluator::Flags & (HereditaryBits|LinearAccessMask) & ~RowMajorBit) | (traits::Flags & RowMajorBit), + + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& replicate) + : m_arg(replicate.nestedExpression()), + m_argImpl(m_arg), + m_rows(replicate.nestedExpression().rows()), + m_cols(replicate.nestedExpression().cols()) + {} + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + // try to avoid using modulo; this is a pure optimization strategy + const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 + : RowFactor==1 ? row + : row % m_rows.value(); + const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 + : ColFactor==1 ? col + : col % m_cols.value(); + + return m_argImpl.coeff(actual_row, actual_col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + // try to avoid using modulo; this is a pure optimization strategy + const Index actual_index = internal::traits::RowsAtCompileTime==1 + ? (ColFactor==1 ? index : index%m_cols.value()) + : (RowFactor==1 ? index : index%m_rows.value()); + + return m_argImpl.coeff(actual_index); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 + : RowFactor==1 ? row + : row % m_rows.value(); + const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 + : ColFactor==1 ? col + : col % m_cols.value(); + + return m_argImpl.template packet(actual_row, actual_col); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + const Index actual_index = internal::traits::RowsAtCompileTime==1 + ? (ColFactor==1 ? index : index%m_cols.value()) + : (RowFactor==1 ? index : index%m_rows.value()); + + return m_argImpl.template packet(actual_index); + } + +protected: + const ArgTypeNested m_arg; + evaluator m_argImpl; + const variable_if_dynamic m_rows; + const variable_if_dynamic m_cols; +}; + + +// -------------------- PartialReduxExpr -------------------- + +template< typename ArgType, typename MemberOp, int Direction> +struct evaluator > + : evaluator_base > +{ + typedef PartialReduxExpr XprType; + typedef typename internal::nested_eval::type ArgTypeNested; + typedef typename internal::remove_all::type ArgTypeNestedCleaned; + typedef typename ArgType::Scalar InputScalar; + typedef typename XprType::Scalar Scalar; + enum { + TraversalSize = Direction==int(Vertical) ? int(ArgType::RowsAtCompileTime) : int(ArgType::ColsAtCompileTime) + }; + typedef typename MemberOp::template Cost CostOpType; + enum { + CoeffReadCost = TraversalSize==Dynamic ? HugeCost + : TraversalSize * evaluator::CoeffReadCost + int(CostOpType::value), + + Flags = (traits::Flags&RowMajorBit) | (evaluator::Flags&(HereditaryBits&(~RowMajorBit))) | LinearAccessBit, + + Alignment = 0 // FIXME this will need to be improved once PartialReduxExpr is vectorized + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType xpr) + : m_arg(xpr.nestedExpression()), m_functor(xpr.functor()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(TraversalSize==Dynamic ? HugeCost : int(CostOpType::value)); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const Scalar coeff(Index i, Index j) const + { + if (Direction==Vertical) + return m_functor(m_arg.col(j)); + else + return m_functor(m_arg.row(i)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const Scalar coeff(Index index) const + { + if (Direction==Vertical) + return m_functor(m_arg.col(index)); + else + return m_functor(m_arg.row(index)); + } + +protected: + typename internal::add_const_on_value_type::type m_arg; + const MemberOp m_functor; +}; + + +// -------------------- MatrixWrapper and ArrayWrapper -------------------- +// +// evaluator_wrapper_base is a common base class for the +// MatrixWrapper and ArrayWrapper evaluators. + +template +struct evaluator_wrapper_base + : evaluator_base +{ + typedef typename remove_all::type ArgType; + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = evaluator::Flags, + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC explicit evaluator_wrapper_base(const ArgType& arg) : m_argImpl(arg) {} + + typedef typename ArgType::Scalar Scalar; + typedef typename ArgType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(row, col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_argImpl.coeff(index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(row, col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return m_argImpl.coeffRef(index); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_argImpl.template packet(row, col); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return m_argImpl.template packet(index); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + m_argImpl.template writePacket(row, col, x); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + m_argImpl.template writePacket(index, x); + } + +protected: + evaluator m_argImpl; +}; + +template +struct unary_evaluator > + : evaluator_wrapper_base > +{ + typedef MatrixWrapper XprType; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& wrapper) + : evaluator_wrapper_base >(wrapper.nestedExpression()) + { } +}; + +template +struct unary_evaluator > + : evaluator_wrapper_base > +{ + typedef ArrayWrapper XprType; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& wrapper) + : evaluator_wrapper_base >(wrapper.nestedExpression()) + { } +}; + + +// -------------------- Reverse -------------------- + +// defined in Reverse.h: +template struct reverse_packet_cond; + +template +struct unary_evaluator > + : evaluator_base > +{ + typedef Reverse XprType; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + enum { + IsRowMajor = XprType::IsRowMajor, + IsColMajor = !IsRowMajor, + ReverseRow = (Direction == Vertical) || (Direction == BothDirections), + ReverseCol = (Direction == Horizontal) || (Direction == BothDirections), + ReversePacket = (Direction == BothDirections) + || ((Direction == Vertical) && IsColMajor) + || ((Direction == Horizontal) && IsRowMajor), + + CoeffReadCost = evaluator::CoeffReadCost, + + // let's enable LinearAccess only with vectorization because of the product overhead + // FIXME enable DirectAccess with negative strides? + Flags0 = evaluator::Flags, + LinearAccess = ( (Direction==BothDirections) && (int(Flags0)&PacketAccessBit) ) + || ((ReverseRow && XprType::ColsAtCompileTime==1) || (ReverseCol && XprType::RowsAtCompileTime==1)) + ? LinearAccessBit : 0, + + Flags = int(Flags0) & (HereditaryBits | PacketAccessBit | LinearAccess), + + Alignment = 0 // FIXME in some rare cases, Alignment could be preserved, like a Vector4f. + }; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& reverse) + : m_argImpl(reverse.nestedExpression()), + m_rows(ReverseRow ? reverse.nestedExpression().rows() : 1), + m_cols(ReverseCol ? reverse.nestedExpression().cols() : 1) + { } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(ReverseRow ? m_rows.value() - row - 1 : row, + ReverseCol ? m_cols.value() - col - 1 : col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_argImpl.coeff(m_rows.value() * m_cols.value() - index - 1); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(ReverseRow ? m_rows.value() - row - 1 : row, + ReverseCol ? m_cols.value() - col - 1 : col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return m_argImpl.coeffRef(m_rows.value() * m_cols.value() - index - 1); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + enum { + PacketSize = unpacket_traits::size, + OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, + OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1 + }; + typedef internal::reverse_packet_cond reverse_packet; + return reverse_packet::run(m_argImpl.template packet( + ReverseRow ? m_rows.value() - row - OffsetRow : row, + ReverseCol ? m_cols.value() - col - OffsetCol : col)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + enum { PacketSize = unpacket_traits::size }; + return preverse(m_argImpl.template packet(m_rows.value() * m_cols.value() - index - PacketSize)); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + // FIXME we could factorize some code with packet(i,j) + enum { + PacketSize = unpacket_traits::size, + OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, + OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1 + }; + typedef internal::reverse_packet_cond reverse_packet; + m_argImpl.template writePacket( + ReverseRow ? m_rows.value() - row - OffsetRow : row, + ReverseCol ? m_cols.value() - col - OffsetCol : col, + reverse_packet::run(x)); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + enum { PacketSize = unpacket_traits::size }; + m_argImpl.template writePacket + (m_rows.value() * m_cols.value() - index - PacketSize, preverse(x)); + } + +protected: + evaluator m_argImpl; + + // If we do not reverse rows, then we do not need to know the number of rows; same for columns + // Nonetheless, in this case it is important to set to 1 such that the coeff(index) method works fine for vectors. + const variable_if_dynamic m_rows; + const variable_if_dynamic m_cols; +}; + + +// -------------------- Diagonal -------------------- + +template +struct evaluator > + : evaluator_base > +{ + typedef Diagonal XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + + Flags = (unsigned int)(evaluator::Flags & (HereditaryBits | DirectAccessBit) & ~RowMajorBit) | LinearAccessBit, + + Alignment = 0 + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& diagonal) + : m_argImpl(diagonal.nestedExpression()), + m_index(diagonal.index()) + { } + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index) const + { + return m_argImpl.coeff(row + rowOffset(), row + colOffset()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_argImpl.coeff(index + rowOffset(), index + colOffset()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index) + { + return m_argImpl.coeffRef(row + rowOffset(), row + colOffset()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return m_argImpl.coeffRef(index + rowOffset(), index + colOffset()); + } + +protected: + evaluator m_argImpl; + const internal::variable_if_dynamicindex m_index; + +private: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rowOffset() const { return m_index.value() > 0 ? 0 : -m_index.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index colOffset() const { return m_index.value() > 0 ? m_index.value() : 0; } +}; + + +//---------------------------------------------------------------------- +// deprecated code +//---------------------------------------------------------------------- + +// -------------------- EvalToTemp -------------------- + +// expression class for evaluating nested expression to a temporary + +template class EvalToTemp; + +template +struct traits > + : public traits +{ }; + +template +class EvalToTemp + : public dense_xpr_base >::type +{ + public: + + typedef typename dense_xpr_base::type Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(EvalToTemp) + + explicit EvalToTemp(const ArgType& arg) + : m_arg(arg) + { } + + const ArgType& arg() const + { + return m_arg; + } + + Index rows() const + { + return m_arg.rows(); + } + + Index cols() const + { + return m_arg.cols(); + } + + private: + const ArgType& m_arg; +}; + +template +struct evaluator > + : public evaluator +{ + typedef EvalToTemp XprType; + typedef typename ArgType::PlainObject PlainObject; + typedef evaluator Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) + : m_result(xpr.arg()) + { + ::new (static_cast(this)) Base(m_result); + } + + // This constructor is used when nesting an EvalTo evaluator in another evaluator + EIGEN_DEVICE_FUNC evaluator(const ArgType& arg) + : m_result(arg) + { + ::new (static_cast(this)) Base(m_result); + } + +protected: + PlainObject m_result; +}; + +} // namespace internal + +} // end namespace Eigen + +#endif // EIGEN_COREEVALUATORS_H diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/CoreIterators.h b/splinter/thirdparty/Eigen/Eigen/src/Core/CoreIterators.h new file mode 100644 index 0000000000..4eb42b93af --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/CoreIterators.h @@ -0,0 +1,127 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2014 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 + */ + +namespace internal { + +template +class inner_iterator_selector; + +} + +/** \class InnerIterator + * \brief An InnerIterator allows to loop over the element of any matrix expression. + * + * \warning To be used with care because an evaluator is constructed every time an InnerIterator iterator is constructed. + * + * TODO: add a usage example + */ +template +class InnerIterator +{ +protected: + typedef internal::inner_iterator_selector::Kind> IteratorType; + typedef internal::evaluator EvaluatorType; + typedef typename internal::traits::Scalar Scalar; +public: + /** Construct an iterator over the \a outerId -th row or column of \a xpr */ + InnerIterator(const XprType &xpr, const Index &outerId) + : m_eval(xpr), m_iter(m_eval, outerId, xpr.innerSize()) + {} + + /// \returns the value of the current coefficient. + EIGEN_STRONG_INLINE Scalar value() const { return m_iter.value(); } + /** Increment the iterator \c *this to the next non-zero coefficient. + * Explicit zeros are not skipped over. To skip explicit zeros, see class SparseView + */ + EIGEN_STRONG_INLINE InnerIterator& operator++() { m_iter.operator++(); return *this; } + /// \returns the column or row index of the current coefficient. + EIGEN_STRONG_INLINE Index index() const { return m_iter.index(); } + /// \returns the row index of the current coefficient. + EIGEN_STRONG_INLINE Index row() const { return m_iter.row(); } + /// \returns the column index of the current coefficient. + EIGEN_STRONG_INLINE Index col() const { return m_iter.col(); } + /// \returns \c true if the iterator \c *this still references a valid coefficient. + EIGEN_STRONG_INLINE operator bool() const { return m_iter; } + +protected: + EvaluatorType m_eval; + IteratorType m_iter; +private: + // If you get here, then you're not using the right InnerIterator type, e.g.: + // SparseMatrix A; + // SparseMatrix::InnerIterator it(A,0); + template InnerIterator(const EigenBase&,Index outer); +}; + +namespace internal { + +// Generic inner iterator implementation for dense objects +template +class inner_iterator_selector +{ +protected: + typedef evaluator EvaluatorType; + typedef typename traits::Scalar Scalar; + enum { IsRowMajor = (XprType::Flags&RowMajorBit)==RowMajorBit }; + +public: + EIGEN_STRONG_INLINE inner_iterator_selector(const EvaluatorType &eval, const Index &outerId, const Index &innerSize) + : m_eval(eval), m_inner(0), m_outer(outerId), m_end(innerSize) + {} + + EIGEN_STRONG_INLINE Scalar value() const + { + return (IsRowMajor) ? m_eval.coeff(m_outer, m_inner) + : m_eval.coeff(m_inner, m_outer); + } + + EIGEN_STRONG_INLINE inner_iterator_selector& 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 EvaluatorType& m_eval; + Index m_inner; + const Index m_outer; + const Index m_end; +}; + +// For iterator-based evaluator, inner-iterator is already implemented as +// evaluator<>::InnerIterator +template +class inner_iterator_selector + : public evaluator::InnerIterator +{ +protected: + typedef typename evaluator::InnerIterator Base; + typedef evaluator EvaluatorType; + +public: + EIGEN_STRONG_INLINE inner_iterator_selector(const EvaluatorType &eval, const Index &outerId, const Index &/*innerSize*/) + : Base(eval, outerId) + {} +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_COREITERATORS_H diff --git a/splinter/src/Core/CwiseBinaryOp.h b/splinter/thirdparty/Eigen/Eigen/src/Core/CwiseBinaryOp.h similarity index 50% rename from splinter/src/Core/CwiseBinaryOp.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/CwiseBinaryOp.h index 519a866e60..a36765e396 100644 --- a/splinter/src/Core/CwiseBinaryOp.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/CwiseBinaryOp.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla @@ -13,26 +13,6 @@ namespace Eigen { -/** \class CwiseBinaryOp - * \ingroup Core_Module - * - * \brief Generic expression where a coefficient-wise binary operator is applied to two expressions - * - * \param BinaryOp template functor implementing the operator - * \param Lhs the type of the left-hand side - * \param Rhs the type of the right-hand side - * - * This class represents an expression where a coefficient-wise binary operator is applied to two expressions. - * It is the return type of binary operators, by which we mean only those binary operators where - * both the left-hand side and the right-hand side are Eigen expressions. - * For example, the return type of matrix1+matrix2 is a CwiseBinaryOp. - * - * Most of the time, this is the only way that it is used, so you typically don't have to name - * CwiseBinaryOp types explicitly. - * - * \sa MatrixBase::binaryExpr(const MatrixBase &,const CustomBinaryOp &) const, class CwiseUnaryOp, class CwiseNullaryOp - */ - namespace internal { template struct traits > @@ -52,77 +32,75 @@ struct traits > // we still want to handle the case when the result type is different. typedef typename result_of< BinaryOp( - typename Lhs::Scalar, - typename Rhs::Scalar + const typename Lhs::Scalar&, + const typename Rhs::Scalar& ) >::type Scalar; - typedef typename promote_storage_type::StorageKind, - typename traits::StorageKind>::ret StorageKind; - typedef typename promote_index_type::Index, - typename traits::Index>::type Index; + typedef typename cwise_promote_storage_type::StorageKind, + typename traits::StorageKind, + BinaryOp>::ret StorageKind; + typedef typename promote_index_type::StorageIndex, + typename traits::StorageIndex>::type StorageIndex; typedef typename Lhs::Nested LhsNested; typedef typename Rhs::Nested RhsNested; typedef typename remove_reference::type _LhsNested; typedef typename remove_reference::type _RhsNested; enum { - LhsCoeffReadCost = _LhsNested::CoeffReadCost, - RhsCoeffReadCost = _RhsNested::CoeffReadCost, - LhsFlags = _LhsNested::Flags, - RhsFlags = _RhsNested::Flags, - SameType = is_same::value, - StorageOrdersAgree = (int(Lhs::Flags)&RowMajorBit)==(int(Rhs::Flags)&RowMajorBit), - Flags0 = (int(LhsFlags) | int(RhsFlags)) & ( - HereditaryBits - | (int(LhsFlags) & int(RhsFlags) & - ( AlignedBit - | (StorageOrdersAgree ? LinearAccessBit : 0) - | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) - ) - ) - ), - Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit), - Cost0 = EIGEN_ADD_COST(LhsCoeffReadCost,RhsCoeffReadCost), - CoeffReadCost = EIGEN_ADD_COST(Cost0,functor_traits::Cost) + Flags = cwise_promote_storage_order::StorageKind,typename traits::StorageKind,_LhsNested::Flags & RowMajorBit,_RhsNested::Flags & RowMajorBit>::value }; }; } // end namespace internal -// we require Lhs and Rhs to have the same scalar type. Currently there is no example of a binary functor -// that would take two operands of different types. If there were such an example, then this check should be -// moved to the BinaryOp functors, on a per-case basis. This would however require a change in the BinaryOp functors, as -// currently they take only one typename Scalar template parameter. -// It is tempting to always allow mixing different types but remember that this is often impossible in the vectorized paths. -// So allowing mixing different types gives very unexpected errors when enabling vectorization, when the user tries to -// add together a float matrix and a double matrix. -#define EIGEN_CHECK_BINARY_COMPATIBILIY(BINOP,LHS,RHS) \ - EIGEN_STATIC_ASSERT((internal::functor_is_product_like::ret \ - ? int(internal::scalar_product_traits::Defined) \ - : int(internal::is_same::value)), \ - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - template class CwiseBinaryOpImpl; -template -class CwiseBinaryOp : internal::no_assignment_operator, +/** \class CwiseBinaryOp + * \ingroup Core_Module + * + * \brief Generic expression where a coefficient-wise binary operator is applied to two expressions + * + * \tparam BinaryOp template functor implementing the operator + * \tparam LhsType the type of the left-hand side + * \tparam RhsType the type of the right-hand side + * + * This class represents an expression where a coefficient-wise binary operator is applied to two expressions. + * It is the return type of binary operators, by which we mean only those binary operators where + * both the left-hand side and the right-hand side are Eigen expressions. + * For example, the return type of matrix1+matrix2 is a CwiseBinaryOp. + * + * Most of the time, this is the only way that it is used, so you typically don't have to name + * CwiseBinaryOp types explicitly. + * + * \sa MatrixBase::binaryExpr(const MatrixBase &,const CustomBinaryOp &) const, class CwiseUnaryOp, class CwiseNullaryOp + */ +template +class CwiseBinaryOp : public CwiseBinaryOpImpl< - BinaryOp, Lhs, Rhs, - typename internal::promote_storage_type::StorageKind, - typename internal::traits::StorageKind>::ret> + BinaryOp, LhsType, RhsType, + typename internal::cwise_promote_storage_type::StorageKind, + typename internal::traits::StorageKind, + BinaryOp>::ret>, + internal::no_assignment_operator { public: + + typedef typename internal::remove_all::type Functor; + typedef typename internal::remove_all::type Lhs; + typedef typename internal::remove_all::type Rhs; typedef typename CwiseBinaryOpImpl< - BinaryOp, Lhs, Rhs, - typename internal::promote_storage_type::StorageKind, - typename internal::traits::StorageKind>::ret>::Base Base; + BinaryOp, LhsType, RhsType, + typename internal::cwise_promote_storage_type::StorageKind, + typename internal::traits::StorageKind, + BinaryOp>::ret>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp) - typedef typename internal::nested::type LhsNested; - typedef typename internal::nested::type RhsNested; + typedef typename internal::ref_selector::type LhsNested; + typedef typename internal::ref_selector::type RhsNested; typedef typename internal::remove_reference::type _LhsNested; typedef typename internal::remove_reference::type _RhsNested; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CwiseBinaryOp(const Lhs& aLhs, const Rhs& aRhs, const BinaryOp& func = BinaryOp()) : m_lhs(aLhs), m_rhs(aRhs), m_functor(func) { @@ -132,6 +110,7 @@ class CwiseBinaryOp : internal::no_assignment_operator, eigen_assert(aLhs.rows() == aRhs.rows() && aLhs.cols() == aRhs.cols()); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { // return the fixed size type if available to enable compile time optimizations if (internal::traits::type>::RowsAtCompileTime==Dynamic) @@ -139,6 +118,7 @@ class CwiseBinaryOp : internal::no_assignment_operator, else return m_lhs.rows(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { // return the fixed size type if available to enable compile time optimizations if (internal::traits::type>::ColsAtCompileTime==Dynamic) @@ -148,10 +128,13 @@ class CwiseBinaryOp : internal::no_assignment_operator, } /** \returns the left hand side nested expression */ + EIGEN_DEVICE_FUNC const _LhsNested& lhs() const { return m_lhs; } /** \returns the right hand side nested expression */ + EIGEN_DEVICE_FUNC const _RhsNested& rhs() const { return m_rhs; } /** \returns the functor representing the binary operation */ + EIGEN_DEVICE_FUNC const BinaryOp& functor() const { return m_functor; } protected: @@ -160,41 +143,13 @@ class CwiseBinaryOp : internal::no_assignment_operator, const BinaryOp m_functor; }; -template -class CwiseBinaryOpImpl - : public internal::dense_xpr_base >::type +// Generic API dispatcher +template +class CwiseBinaryOpImpl + : public internal::generic_xpr_base >::type { - typedef CwiseBinaryOp Derived; - public: - - typedef typename internal::dense_xpr_base >::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE( Derived ) - - EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const - { - return derived().functor()(derived().lhs().coeff(rowId, colId), - derived().rhs().coeff(rowId, colId)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const - { - return derived().functor().packetOp(derived().lhs().template packet(rowId, colId), - derived().rhs().template packet(rowId, colId)); - } - - EIGEN_STRONG_INLINE const Scalar coeff(Index index) const - { - return derived().functor()(derived().lhs().coeff(index), - derived().rhs().coeff(index)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index index) const - { - return derived().functor().packetOp(derived().lhs().template packet(index), - derived().rhs().template packet(index)); - } +public: + typedef typename internal::generic_xpr_base >::type Base; }; /** replaces \c *this by \c *this - \a other. @@ -206,8 +161,7 @@ template EIGEN_STRONG_INLINE Derived & MatrixBase::operator-=(const MatrixBase &other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::sub_assign_op()); return derived(); } @@ -220,11 +174,11 @@ template EIGEN_STRONG_INLINE Derived & MatrixBase::operator+=(const MatrixBase& other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::add_assign_op()); return derived(); } } // end namespace Eigen #endif // EIGEN_CWISE_BINARY_OP_H + diff --git a/splinter/src/Core/CwiseNullaryOp.h b/splinter/thirdparty/Eigen/Eigen/src/Core/CwiseNullaryOp.h similarity index 67% rename from splinter/src/Core/CwiseNullaryOp.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/CwiseNullaryOp.h index a93bab2d0f..ddd607e383 100644 --- a/splinter/src/Core/CwiseNullaryOp.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/CwiseNullaryOp.h @@ -12,13 +12,24 @@ namespace Eigen { +namespace internal { +template +struct traits > : traits +{ + enum { + Flags = traits::Flags & RowMajorBit + }; +}; + +} // namespace internal + /** \class CwiseNullaryOp * \ingroup Core_Module * * \brief Generic expression of a matrix where all coefficients are defined by a functor * - * \param NullaryOp template functor implementing the operator - * \param PlainObjectType the underlying plain matrix/array type + * \tparam NullaryOp template functor implementing the operator + * \tparam PlainObjectType the underlying plain matrix/array type * * This class represents an expression of a generic nullary operator. * It is the return type of the Ones(), Zero(), Constant(), Identity() and Random() methods, @@ -27,68 +38,49 @@ namespace Eigen { * However, if you want to write a function returning such an expression, you * will need to use this class. * - * \sa class CwiseUnaryOp, class CwiseBinaryOp, DenseBase::NullaryExpr() + * The functor NullaryOp must expose one of the following method: + + + + +
\c operator()() if the procedural generation does not depend on the coefficient entries (e.g., random numbers)
\c operator()(Index i)if the procedural generation makes sense for vectors only and that it depends on the coefficient index \c i (e.g., linspace)
\c operator()(Index i,Index j)if the procedural generation depends on the matrix coordinates \c i, \c j (e.g., to generate a checkerboard with 0 and 1)
+ * It is also possible to expose the last two operators if the generation makes sense for matrices but can be optimized for vectors. + * + * See DenseBase::NullaryExpr(Index,const CustomNullaryOp&) for an example binding + * C++11 random number generators. + * + * A nullary expression can also be used to implement custom sophisticated matrix manipulations + * that cannot be covered by the existing set of natively supported matrix manipulations. + * See this \ref TopicCustomizing_NullaryExpr "page" for some examples and additional explanations + * on the behavior of CwiseNullaryOp. + * + * \sa class CwiseUnaryOp, class CwiseBinaryOp, DenseBase::NullaryExpr */ - -namespace internal { template -struct traits > : traits -{ - enum { - Flags = (traits::Flags - & ( HereditaryBits - | (functor_has_linear_access::ret ? LinearAccessBit : 0) - | (functor_traits::PacketAccess ? PacketAccessBit : 0))) - | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit), - CoeffReadCost = functor_traits::Cost - }; -}; -} - -template -class CwiseNullaryOp : internal::no_assignment_operator, - public internal::dense_xpr_base< CwiseNullaryOp >::type +class CwiseNullaryOp : public internal::dense_xpr_base< CwiseNullaryOp >::type, internal::no_assignment_operator { public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(CwiseNullaryOp) - CwiseNullaryOp(Index nbRows, Index nbCols, const NullaryOp& func = NullaryOp()) - : m_rows(nbRows), m_cols(nbCols), m_functor(func) + EIGEN_DEVICE_FUNC + CwiseNullaryOp(Index rows, Index cols, const NullaryOp& func = NullaryOp()) + : m_rows(rows), m_cols(cols), m_functor(func) { - eigen_assert(nbRows >= 0 - && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == nbRows) - && nbCols >= 0 - && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == nbCols)); + eigen_assert(rows >= 0 + && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows) + && cols >= 0 + && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols)); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return m_rows.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_cols.value(); } - EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const - { - return m_functor(rowId, colId); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const - { - return m_functor.packetOp(rowId, colId); - } - - EIGEN_STRONG_INLINE const Scalar coeff(Index index) const - { - return m_functor(index); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index index) const - { - return m_functor.packetOp(index); - } - /** \returns the functor representing the nullary operation */ + EIGEN_DEVICE_FUNC const NullaryOp& functor() const { return m_functor; } protected: @@ -113,10 +105,10 @@ class CwiseNullaryOp : internal::no_assignment_operator, */ template template -EIGEN_STRONG_INLINE const CwiseNullaryOp +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseNullaryOp::PlainObject> DenseBase::NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func) { - return CwiseNullaryOp(rows, cols, func); + return CwiseNullaryOp(rows, cols, func); } /** \returns an expression of a matrix defined by a custom functor \a func @@ -132,16 +124,19 @@ DenseBase::NullaryExpr(Index rows, Index cols, const CustomNullaryOp& f * * The template parameter \a CustomNullaryOp is the type of the functor. * + * Here is an example with C++11 random generators: \include random_cpp11.cpp + * Output: \verbinclude random_cpp11.out + * * \sa class CwiseNullaryOp */ template template -EIGEN_STRONG_INLINE const CwiseNullaryOp +EIGEN_STRONG_INLINE const CwiseNullaryOp::PlainObject> DenseBase::NullaryExpr(Index size, const CustomNullaryOp& func) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - if(RowsAtCompileTime == 1) return CwiseNullaryOp(1, size, func); - else return CwiseNullaryOp(size, 1, func); + if(RowsAtCompileTime == 1) return CwiseNullaryOp(1, size, func); + else return CwiseNullaryOp(size, 1, func); } /** \returns an expression of a matrix defined by a custom functor \a func @@ -155,19 +150,19 @@ DenseBase::NullaryExpr(Index size, const CustomNullaryOp& func) */ template template -EIGEN_STRONG_INLINE const CwiseNullaryOp +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseNullaryOp::PlainObject> DenseBase::NullaryExpr(const CustomNullaryOp& func) { - return CwiseNullaryOp(RowsAtCompileTime, ColsAtCompileTime, func); + return CwiseNullaryOp(RowsAtCompileTime, ColsAtCompileTime, func); } /** \returns an expression of a constant matrix of value \a value * - * The parameters \a nbRows and \a nbCols are the number of rows and of columns of + * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this DenseBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, - * it is redundant to pass \a nbRows and \a nbCols as arguments, so Zero() should be used + * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used * instead. * * The template parameter \a CustomNullaryOp is the type of the functor. @@ -176,9 +171,9 @@ DenseBase::NullaryExpr(const CustomNullaryOp& func) */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Constant(Index nbRows, Index nbCols, const Scalar& value) +DenseBase::Constant(Index rows, Index cols, const Scalar& value) { - return DenseBase::NullaryExpr(nbRows, nbCols, internal::scalar_constant_op(value)); + return DenseBase::NullaryExpr(rows, cols, internal::scalar_constant_op(value)); } /** \returns an expression of a constant matrix of value \a value @@ -197,7 +192,7 @@ DenseBase::Constant(Index nbRows, Index nbCols, const Scalar& value) * \sa class CwiseNullaryOp */ template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Constant(Index size, const Scalar& value) { return DenseBase::NullaryExpr(size, internal::scalar_constant_op(value)); @@ -213,53 +208,40 @@ DenseBase::Constant(Index size, const Scalar& value) * \sa class CwiseNullaryOp */ template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Constant(const Scalar& value) { EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) return DenseBase::NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_constant_op(value)); } -/** - * \brief Sets a linearly space vector. - * - * The function generates 'size' equally spaced values in the closed interval [low,high]. - * This particular version of LinSpaced() uses sequential access, i.e. vector access is - * 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 - * Output: \verbinclude DenseBase_LinSpaced_seq.out +/** \deprecated because of accuracy loss. In Eigen 3.3, it is an alias for LinSpaced(Index,const Scalar&,const Scalar&) * - * \sa setLinSpaced(Index,const Scalar&,const Scalar&), LinSpaced(Index,Scalar,Scalar), CwiseNullaryOp + * \sa LinSpaced(Index,Scalar,Scalar), setLinSpaced(Index,const Scalar&,const Scalar&) */ template -EIGEN_STRONG_INLINE const typename DenseBase::SequentialLinSpacedReturnType +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType DenseBase::LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); + return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); } -/** - * \copydoc DenseBase::LinSpaced(Sequential_t, Index, const Scalar&, const Scalar&) - * Special version for fixed size types which does not require the size parameter. +/** \deprecated because of accuracy loss. In Eigen 3.3, it is an alias for LinSpaced(const Scalar&,const Scalar&) + * + * \sa LinSpaced(Scalar,Scalar) */ template -EIGEN_STRONG_INLINE const typename DenseBase::SequentialLinSpacedReturnType +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType DenseBase::LinSpaced(Sequential_t, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) - return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); + return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); } /** - * \brief Sets a linearly space vector. + * \brief Sets a linearly spaced 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. @@ -269,14 +251,24 @@ DenseBase::LinSpaced(Sequential_t, const Scalar& low, const Scalar& hig * Example: \include DenseBase_LinSpaced.cpp * Output: \verbinclude DenseBase_LinSpaced.out * - * \sa setLinSpaced(Index,const Scalar&,const Scalar&), LinSpaced(Sequential_t,Index,const Scalar&,const Scalar&,Index), CwiseNullaryOp + * For integer scalar types, an even spacing is possible if and only if the length of the range, + * i.e., \c high-low is a scalar multiple of \c size-1, or if \c size is a scalar multiple of the + * number of values \c high-low+1 (meaning each value can be repeated the same number of time). + * If one of these two considions is not satisfied, then \c high is lowered to the largest value + * satisfying one of this constraint. + * Here are some examples: + * + * Example: \include DenseBase_LinSpacedInt.cpp + * Output: \verbinclude DenseBase_LinSpacedInt.out + * + * \sa setLinSpaced(Index,const Scalar&,const Scalar&), CwiseNullaryOp */ template -EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType DenseBase::LinSpaced(Index size, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); + return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); } /** @@ -284,22 +276,23 @@ DenseBase::LinSpaced(Index size, const Scalar& low, const Scalar& high) * Special version for fixed size types which does not require the size parameter. */ template -EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType DenseBase::LinSpaced(const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) - return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); + return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); } /** \returns true if all coefficients in this matrix are approximately equal to \a val, to within precision \a prec */ template -bool DenseBase::isApproxToConstant +EIGEN_DEVICE_FUNC bool DenseBase::isApproxToConstant (const Scalar& val, const RealScalar& prec) const { + typename internal::nested_eval::type self(derived()); for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) - if(!internal::isApprox(this->coeff(i, j), val, prec)) + if(!internal::isApprox(self.coeff(i, j), val, prec)) return false; return true; } @@ -308,7 +301,7 @@ bool DenseBase::isApproxToConstant * * \returns true if all coefficients in this matrix are approximately equal to \a value, to within precision \a prec */ template -bool DenseBase::isConstant +EIGEN_DEVICE_FUNC bool DenseBase::isConstant (const Scalar& val, const RealScalar& prec) const { return isApproxToConstant(val, prec); @@ -319,22 +312,22 @@ bool DenseBase::isConstant * \sa setConstant(), Constant(), class CwiseNullaryOp */ template -EIGEN_STRONG_INLINE void DenseBase::fill(const Scalar& val) +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void DenseBase::fill(const Scalar& val) { setConstant(val); } -/** Sets all coefficients in this expression to \a value. +/** Sets all coefficients in this expression to value \a val. * * \sa fill(), setConstant(Index,const Scalar&), setConstant(Index,Index,const Scalar&), setZero(), setOnes(), Constant(), class CwiseNullaryOp, setZero(), setOnes() */ template -EIGEN_STRONG_INLINE Derived& DenseBase::setConstant(const Scalar& val) +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::setConstant(const Scalar& val) { return derived() = Constant(rows(), cols(), val); } -/** Resizes to the given \a size, and sets all coefficients in this expression to the given \a value. +/** Resizes to the given \a size, and sets all coefficients in this expression to the given value \a val. * * \only_for_vectors * @@ -344,17 +337,17 @@ EIGEN_STRONG_INLINE Derived& DenseBase::setConstant(const Scalar& val) * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&) */ template -EIGEN_STRONG_INLINE Derived& +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& PlainObjectBase::setConstant(Index size, const Scalar& val) { resize(size); return setConstant(val); } -/** Resizes to the given size, and sets all coefficients in this expression to the given \a value. +/** Resizes to the given size, and sets all coefficients in this expression to the given value \a val. * - * \param nbRows the new number of rows - * \param nbCols the new number of columns + * \param rows the new number of rows + * \param cols the new number of columns * \param val the value to which all coefficients are set * * Example: \include Matrix_setConstant_int_int.cpp @@ -363,15 +356,15 @@ PlainObjectBase::setConstant(Index size, const Scalar& val) * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&) */ template -EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setConstant(Index nbRows, Index nbCols, const Scalar& val) +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setConstant(Index rows, Index cols, const Scalar& val) { - resize(nbRows, nbCols); + resize(rows, cols); return setConstant(val); } /** - * \brief Sets a linearly space vector. + * \brief Sets a linearly spaced 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. @@ -381,27 +374,33 @@ PlainObjectBase::setConstant(Index nbRows, Index nbCols, const Scalar& * Example: \include DenseBase_setLinSpaced.cpp * Output: \verbinclude DenseBase_setLinSpaced.out * - * \sa CwiseNullaryOp + * For integer scalar types, do not miss the explanations on the definition + * of \link LinSpaced(Index,const Scalar&,const Scalar&) even spacing \endlink. + * + * \sa LinSpaced(Index,const Scalar&,const Scalar&), CwiseNullaryOp */ template -EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(Index newSize, const Scalar& low, const Scalar& high) +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(Index newSize, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return derived() = Derived::NullaryExpr(newSize, internal::linspaced_op(low,high,newSize)); + return derived() = Derived::NullaryExpr(newSize, internal::linspaced_op(low,high,newSize)); } /** - * \brief Sets a linearly space vector. + * \brief Sets a linearly spaced vector. * - * The function fill *this with equally spaced values in the closed interval [low,high]. + * The function fills \c *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 + * For integer scalar types, do not miss the explanations on the definition + * of \link LinSpaced(Index,const Scalar&,const Scalar&) even spacing \endlink. + * + * \sa LinSpaced(Index,const Scalar&,const Scalar&), setLinSpaced(Index, const Scalar&, const Scalar&), CwiseNullaryOp */ template -EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(const Scalar& low, const Scalar& high) +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return setLinSpaced(size(), low, high); @@ -424,10 +423,10 @@ EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(const Scalar& low, * \sa Zero(), Zero(Index) */ template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Zero(Index nbRows, Index nbCols) +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Zero(Index rows, Index cols) { - return Constant(nbRows, nbCols, Scalar(0)); + return Constant(rows, cols, Scalar(0)); } /** \returns an expression of a zero vector. @@ -447,7 +446,7 @@ DenseBase::Zero(Index nbRows, Index nbCols) * \sa Zero(), Zero(Index,Index) */ template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Zero(Index size) { return Constant(size, Scalar(0)); @@ -464,7 +463,7 @@ DenseBase::Zero(Index size) * \sa Zero(Index), Zero(Index,Index) */ template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Zero() { return Constant(Scalar(0)); @@ -479,11 +478,12 @@ DenseBase::Zero() * \sa class CwiseNullaryOp, Zero() */ template -bool DenseBase::isZero(const RealScalar& prec) const +EIGEN_DEVICE_FUNC bool DenseBase::isZero(const RealScalar& prec) const { + typename internal::nested_eval::type self(derived()); for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) - if(!internal::isMuchSmallerThan(this->coeff(i, j), static_cast(1), prec)) + if(!internal::isMuchSmallerThan(self.coeff(i, j), static_cast(1), prec)) return false; return true; } @@ -496,7 +496,7 @@ bool DenseBase::isZero(const RealScalar& prec) const * \sa class CwiseNullaryOp, Zero() */ template -EIGEN_STRONG_INLINE Derived& DenseBase::setZero() +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::setZero() { return setConstant(Scalar(0)); } @@ -511,7 +511,7 @@ EIGEN_STRONG_INLINE Derived& DenseBase::setZero() * \sa DenseBase::setZero(), setZero(Index,Index), class CwiseNullaryOp, DenseBase::Zero() */ template -EIGEN_STRONG_INLINE Derived& +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& PlainObjectBase::setZero(Index newSize) { resize(newSize); @@ -520,8 +520,8 @@ PlainObjectBase::setZero(Index newSize) /** Resizes to the given size, and sets all coefficients in this expression to zero. * - * \param nbRows the new number of rows - * \param nbCols the new number of columns + * \param rows the new number of rows + * \param cols the new number of columns * * Example: \include Matrix_setZero_int_int.cpp * Output: \verbinclude Matrix_setZero_int_int.out @@ -529,10 +529,10 @@ PlainObjectBase::setZero(Index newSize) * \sa DenseBase::setZero(), setZero(Index), class CwiseNullaryOp, DenseBase::Zero() */ template -EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setZero(Index nbRows, Index nbCols) +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setZero(Index rows, Index cols) { - resize(nbRows, nbCols); + resize(rows, cols); return setConstant(Scalar(0)); } @@ -540,7 +540,7 @@ PlainObjectBase::setZero(Index nbRows, Index nbCols) /** \returns an expression of a matrix where all coefficients equal one. * - * The parameters \a nbRows and \a nbCols are the number of rows and of columns of + * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, @@ -553,10 +553,10 @@ PlainObjectBase::setZero(Index nbRows, Index nbCols) * \sa Ones(), Ones(Index), isOnes(), class Ones */ template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Ones(Index nbRows, Index nbCols) +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Ones(Index rows, Index cols) { - return Constant(nbRows, nbCols, Scalar(1)); + return Constant(rows, cols, Scalar(1)); } /** \returns an expression of a vector where all coefficients equal one. @@ -576,7 +576,7 @@ DenseBase::Ones(Index nbRows, Index nbCols) * \sa Ones(), Ones(Index,Index), isOnes(), class Ones */ template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Ones(Index newSize) { return Constant(newSize, Scalar(1)); @@ -593,7 +593,7 @@ DenseBase::Ones(Index newSize) * \sa Ones(Index), Ones(Index,Index), isOnes(), class Ones */ template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Ones() { return Constant(Scalar(1)); @@ -608,7 +608,7 @@ DenseBase::Ones() * \sa class CwiseNullaryOp, Ones() */ template -bool DenseBase::isOnes +EIGEN_DEVICE_FUNC bool DenseBase::isOnes (const RealScalar& prec) const { return isApproxToConstant(Scalar(1), prec); @@ -622,7 +622,7 @@ bool DenseBase::isOnes * \sa class CwiseNullaryOp, Ones() */ template -EIGEN_STRONG_INLINE Derived& DenseBase::setOnes() +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::setOnes() { return setConstant(Scalar(1)); } @@ -637,7 +637,7 @@ EIGEN_STRONG_INLINE Derived& DenseBase::setOnes() * \sa MatrixBase::setOnes(), setOnes(Index,Index), class CwiseNullaryOp, MatrixBase::Ones() */ template -EIGEN_STRONG_INLINE Derived& +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& PlainObjectBase::setOnes(Index newSize) { resize(newSize); @@ -646,8 +646,8 @@ PlainObjectBase::setOnes(Index newSize) /** Resizes to the given size, and sets all coefficients in this expression to one. * - * \param nbRows the new number of rows - * \param nbCols the new number of columns + * \param rows the new number of rows + * \param cols the new number of columns * * Example: \include Matrix_setOnes_int_int.cpp * Output: \verbinclude Matrix_setOnes_int_int.out @@ -655,10 +655,10 @@ PlainObjectBase::setOnes(Index newSize) * \sa MatrixBase::setOnes(), setOnes(Index), class CwiseNullaryOp, MatrixBase::Ones() */ template -EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setOnes(Index nbRows, Index nbCols) +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setOnes(Index rows, Index cols) { - resize(nbRows, nbCols); + resize(rows, cols); return setConstant(Scalar(1)); } @@ -666,7 +666,7 @@ PlainObjectBase::setOnes(Index nbRows, Index nbCols) /** \returns an expression of the identity matrix (not necessarily square). * - * The parameters \a nbRows and \a nbCols are the number of rows and of columns of + * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, @@ -679,10 +679,10 @@ PlainObjectBase::setOnes(Index nbRows, Index nbCols) * \sa Identity(), setIdentity(), isIdentity() */ template -EIGEN_STRONG_INLINE const typename MatrixBase::IdentityReturnType -MatrixBase::Identity(Index nbRows, Index nbCols) +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::IdentityReturnType +MatrixBase::Identity(Index rows, Index cols) { - return DenseBase::NullaryExpr(nbRows, nbCols, internal::scalar_identity_op()); + return DenseBase::NullaryExpr(rows, cols, internal::scalar_identity_op()); } /** \returns an expression of the identity matrix (not necessarily square). @@ -696,7 +696,7 @@ MatrixBase::Identity(Index nbRows, Index nbCols) * \sa Identity(Index,Index), setIdentity(), isIdentity() */ template -EIGEN_STRONG_INLINE const typename MatrixBase::IdentityReturnType +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::IdentityReturnType MatrixBase::Identity() { EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) @@ -716,18 +716,19 @@ template bool MatrixBase::isIdentity (const RealScalar& prec) const { + typename internal::nested_eval::type self(derived()); for(Index j = 0; j < cols(); ++j) { for(Index i = 0; i < rows(); ++i) { if(i == j) { - if(!internal::isApprox(this->coeff(i, j), static_cast(1), prec)) + if(!internal::isApprox(self.coeff(i, j), static_cast(1), prec)) return false; } else { - if(!internal::isMuchSmallerThan(this->coeff(i, j), static_cast(1), prec)) + if(!internal::isMuchSmallerThan(self.coeff(i, j), static_cast(1), prec)) return false; } } @@ -740,6 +741,7 @@ namespace internal { template=16)> struct setIdentity_impl { + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Derived& run(Derived& m) { return m = Derived::Identity(m.rows(), m.cols()); @@ -749,11 +751,11 @@ struct setIdentity_impl template struct setIdentity_impl { - typedef typename Derived::Index Index; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Derived& run(Derived& m) { m.setZero(); - const Index size = (std::min)(m.rows(), m.cols()); + const Index size = numext::mini(m.rows(), m.cols()); for(Index i = 0; i < size; ++i) m.coeffRef(i,i) = typename Derived::Scalar(1); return m; } @@ -769,15 +771,15 @@ struct setIdentity_impl * \sa class CwiseNullaryOp, Identity(), Identity(Index,Index), isIdentity() */ template -EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity() +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity() { return internal::setIdentity_impl::run(derived()); } /** \brief Resizes to the given size, and writes the identity expression (not necessarily square) into *this. * - * \param nbRows the new number of rows - * \param nbCols the new number of columns + * \param rows the new number of rows + * \param cols the new number of columns * * Example: \include Matrix_setIdentity_int_int.cpp * Output: \verbinclude Matrix_setIdentity_int_int.out @@ -785,9 +787,9 @@ EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity() * \sa MatrixBase::setIdentity(), class CwiseNullaryOp, MatrixBase::Identity() */ template -EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity(Index nbRows, Index nbCols) +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity(Index rows, Index cols) { - derived().resize(nbRows, nbCols); + derived().resize(rows, cols); return setIdentity(); } @@ -798,7 +800,7 @@ EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity(Index nbRows, Inde * \sa MatrixBase::Unit(Index), MatrixBase::UnitX(), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template -EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::Unit(Index newSize, Index i) +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::Unit(Index newSize, Index i) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return BasisReturnType(SquareMatrixType::Identity(newSize,newSize), i); @@ -813,7 +815,7 @@ EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBa * \sa MatrixBase::Unit(Index,Index), MatrixBase::UnitX(), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template -EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::Unit(Index i) +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::Unit(Index i) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return BasisReturnType(SquareMatrixType::Identity(),i); @@ -826,7 +828,7 @@ EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBa * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template -EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitX() +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitX() { return Derived::Unit(0); } /** \returns an expression of the Y axis unit vector (0,1{,0}^*) @@ -836,7 +838,7 @@ EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBa * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template -EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitY() +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitY() { return Derived::Unit(1); } /** \returns an expression of the Z axis unit vector (0,0,1{,0}^*) @@ -846,7 +848,7 @@ EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBa * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template -EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitZ() +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitZ() { return Derived::Unit(2); } /** \returns an expression of the W axis unit vector (0,0,0,1) @@ -856,7 +858,7 @@ EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBa * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template -EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitW() +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitW() { return Derived::Unit(3); } } // end namespace Eigen diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/CwiseTernaryOp.h b/splinter/thirdparty/Eigen/Eigen/src/Core/CwiseTernaryOp.h new file mode 100644 index 0000000000..9f3576fece --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/CwiseTernaryOp.h @@ -0,0 +1,197 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2014 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2016 Eugene Brevdo +// +// 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_TERNARY_OP_H +#define EIGEN_CWISE_TERNARY_OP_H + +namespace Eigen { + +namespace internal { +template +struct traits > { + // we must not inherit from traits since it has + // the potential to cause problems with MSVC + typedef typename remove_all::type Ancestor; + typedef typename traits::XprKind XprKind; + enum { + RowsAtCompileTime = traits::RowsAtCompileTime, + ColsAtCompileTime = traits::ColsAtCompileTime, + MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = traits::MaxColsAtCompileTime + }; + + // even though we require Arg1, Arg2, and Arg3 to have the same scalar type + // (see CwiseTernaryOp constructor), + // we still want to handle the case when the result type is different. + typedef typename result_of::type Scalar; + + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::StorageIndex StorageIndex; + + typedef typename Arg1::Nested Arg1Nested; + typedef typename Arg2::Nested Arg2Nested; + typedef typename Arg3::Nested Arg3Nested; + typedef typename remove_reference::type _Arg1Nested; + typedef typename remove_reference::type _Arg2Nested; + typedef typename remove_reference::type _Arg3Nested; + enum { Flags = _Arg1Nested::Flags & RowMajorBit }; +}; +} // end namespace internal + +template +class CwiseTernaryOpImpl; + +/** \class CwiseTernaryOp + * \ingroup Core_Module + * + * \brief Generic expression where a coefficient-wise ternary operator is + * applied to two expressions + * + * \tparam TernaryOp template functor implementing the operator + * \tparam Arg1Type the type of the first argument + * \tparam Arg2Type the type of the second argument + * \tparam Arg3Type the type of the third argument + * + * This class represents an expression where a coefficient-wise ternary + * operator is applied to three expressions. + * It is the return type of ternary operators, by which we mean only those + * ternary operators where + * all three arguments are Eigen expressions. + * For example, the return type of betainc(matrix1, matrix2, matrix3) is a + * CwiseTernaryOp. + * + * Most of the time, this is the only way that it is used, so you typically + * don't have to name + * CwiseTernaryOp types explicitly. + * + * \sa MatrixBase::ternaryExpr(const MatrixBase &, const + * MatrixBase &, const CustomTernaryOp &) const, class CwiseBinaryOp, + * class CwiseUnaryOp, class CwiseNullaryOp + */ +template +class CwiseTernaryOp : public CwiseTernaryOpImpl< + TernaryOp, Arg1Type, Arg2Type, Arg3Type, + typename internal::traits::StorageKind>, + internal::no_assignment_operator +{ + public: + typedef typename internal::remove_all::type Arg1; + typedef typename internal::remove_all::type Arg2; + typedef typename internal::remove_all::type Arg3; + + typedef typename CwiseTernaryOpImpl< + TernaryOp, Arg1Type, Arg2Type, Arg3Type, + typename internal::traits::StorageKind>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseTernaryOp) + + typedef typename internal::ref_selector::type Arg1Nested; + typedef typename internal::ref_selector::type Arg2Nested; + typedef typename internal::ref_selector::type Arg3Nested; + typedef typename internal::remove_reference::type _Arg1Nested; + typedef typename internal::remove_reference::type _Arg2Nested; + typedef typename internal::remove_reference::type _Arg3Nested; + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE CwiseTernaryOp(const Arg1& a1, const Arg2& a2, + const Arg3& a3, + const TernaryOp& func = TernaryOp()) + : m_arg1(a1), m_arg2(a2), m_arg3(a3), m_functor(func) { + // require the sizes to match + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Arg1, Arg2) + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Arg1, Arg3) + + // The index types should match + EIGEN_STATIC_ASSERT((internal::is_same< + typename internal::traits::StorageKind, + typename internal::traits::StorageKind>::value), + STORAGE_KIND_MUST_MATCH) + EIGEN_STATIC_ASSERT((internal::is_same< + typename internal::traits::StorageKind, + typename internal::traits::StorageKind>::value), + STORAGE_KIND_MUST_MATCH) + + eigen_assert(a1.rows() == a2.rows() && a1.cols() == a2.cols() && + a1.rows() == a3.rows() && a1.cols() == a3.cols()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Index rows() const { + // return the fixed size type if available to enable compile time + // optimizations + if (internal::traits::type>:: + RowsAtCompileTime == Dynamic && + internal::traits::type>:: + RowsAtCompileTime == Dynamic) + return m_arg3.rows(); + else if (internal::traits::type>:: + RowsAtCompileTime == Dynamic && + internal::traits::type>:: + RowsAtCompileTime == Dynamic) + return m_arg2.rows(); + else + return m_arg1.rows(); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Index cols() const { + // return the fixed size type if available to enable compile time + // optimizations + if (internal::traits::type>:: + ColsAtCompileTime == Dynamic && + internal::traits::type>:: + ColsAtCompileTime == Dynamic) + return m_arg3.cols(); + else if (internal::traits::type>:: + ColsAtCompileTime == Dynamic && + internal::traits::type>:: + ColsAtCompileTime == Dynamic) + return m_arg2.cols(); + else + return m_arg1.cols(); + } + + /** \returns the first argument nested expression */ + EIGEN_DEVICE_FUNC + const _Arg1Nested& arg1() const { return m_arg1; } + /** \returns the first argument nested expression */ + EIGEN_DEVICE_FUNC + const _Arg2Nested& arg2() const { return m_arg2; } + /** \returns the third argument nested expression */ + EIGEN_DEVICE_FUNC + const _Arg3Nested& arg3() const { return m_arg3; } + /** \returns the functor representing the ternary operation */ + EIGEN_DEVICE_FUNC + const TernaryOp& functor() const { return m_functor; } + + protected: + Arg1Nested m_arg1; + Arg2Nested m_arg2; + Arg3Nested m_arg3; + const TernaryOp m_functor; +}; + +// Generic API dispatcher +template +class CwiseTernaryOpImpl + : public internal::generic_xpr_base< + CwiseTernaryOp >::type { + public: + typedef typename internal::generic_xpr_base< + CwiseTernaryOp >::type Base; +}; + +} // end namespace Eigen + +#endif // EIGEN_CWISE_TERNARY_OP_H diff --git a/splinter/src/Core/CwiseUnaryOp.h b/splinter/thirdparty/Eigen/Eigen/src/Core/CwiseUnaryOp.h similarity index 50% rename from splinter/src/Core/CwiseUnaryOp.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/CwiseUnaryOp.h index f7ee60e987..1d2dd19f2b 100644 --- a/splinter/src/Core/CwiseUnaryOp.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/CwiseUnaryOp.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla @@ -13,41 +13,18 @@ namespace Eigen { -/** \class CwiseUnaryOp - * \ingroup Core_Module - * - * \brief Generic expression where a coefficient-wise unary operator is applied to an expression - * - * \param UnaryOp template functor implementing the operator - * \param XprType the type of the expression to which we are applying the unary operator - * - * This class represents an expression where a unary operator is applied to an expression. - * It is the return type of all operations taking exactly 1 input expression, regardless of the - * presence of other inputs such as scalars. For example, the operator* in the expression 3*matrix - * is considered unary, because only the right-hand side is an expression, and its - * return type is a specialization of CwiseUnaryOp. - * - * Most of the time, this is the only way that it is used, so you typically don't have to name - * CwiseUnaryOp types explicitly. - * - * \sa MatrixBase::unaryExpr(const CustomUnaryOp &) const, class CwiseBinaryOp, class CwiseNullaryOp - */ - namespace internal { template struct traits > : traits { typedef typename result_of< - UnaryOp(typename XprType::Scalar) + UnaryOp(const typename XprType::Scalar&) >::type Scalar; typedef typename XprType::Nested XprTypeNested; typedef typename remove_reference::type _XprTypeNested; enum { - Flags = _XprTypeNested::Flags & ( - HereditaryBits | LinearAccessBit | AlignedBit - | (functor_traits::PacketAccess ? PacketAccessBit : 0)), - CoeffReadCost = EIGEN_ADD_COST(_XprTypeNested::CoeffReadCost, functor_traits::Cost) + Flags = _XprTypeNested::Flags & RowMajorBit }; }; } @@ -55,70 +32,70 @@ struct traits > template class CwiseUnaryOpImpl; +/** \class CwiseUnaryOp + * \ingroup Core_Module + * + * \brief Generic expression where a coefficient-wise unary operator is applied to an expression + * + * \tparam UnaryOp template functor implementing the operator + * \tparam XprType the type of the expression to which we are applying the unary operator + * + * This class represents an expression where a unary operator is applied to an expression. + * It is the return type of all operations taking exactly 1 input expression, regardless of the + * presence of other inputs such as scalars. For example, the operator* in the expression 3*matrix + * is considered unary, because only the right-hand side is an expression, and its + * return type is a specialization of CwiseUnaryOp. + * + * Most of the time, this is the only way that it is used, so you typically don't have to name + * CwiseUnaryOp types explicitly. + * + * \sa MatrixBase::unaryExpr(const CustomUnaryOp &) const, class CwiseBinaryOp, class CwiseNullaryOp + */ template -class CwiseUnaryOp : internal::no_assignment_operator, - public CwiseUnaryOpImpl::StorageKind> +class CwiseUnaryOp : public CwiseUnaryOpImpl::StorageKind>, internal::no_assignment_operator { public: typedef typename CwiseUnaryOpImpl::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryOp) + typedef typename internal::ref_selector::type XprTypeNested; + typedef typename internal::remove_all::type NestedExpression; - inline CwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit CwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) : m_xpr(xpr), m_functor(func) {} - EIGEN_STRONG_INLINE Index rows() const { return m_xpr.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_xpr.cols(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Index rows() const { return m_xpr.rows(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Index cols() const { return m_xpr.cols(); } /** \returns the functor representing the unary operation */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const UnaryOp& functor() const { return m_functor; } /** \returns the nested expression */ - const typename internal::remove_all::type& + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const typename internal::remove_all::type& nestedExpression() const { return m_xpr; } /** \returns the nested expression */ - typename internal::remove_all::type& - nestedExpression() { return m_xpr.const_cast_derived(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + typename internal::remove_all::type& + nestedExpression() { return m_xpr; } protected: - typename XprType::Nested m_xpr; + XprTypeNested m_xpr; const UnaryOp m_functor; }; -// This is the generic implementation for dense storage. -// It can be used for any expression types implementing the dense concept. -template -class CwiseUnaryOpImpl - : public internal::dense_xpr_base >::type +// Generic API dispatcher +template +class CwiseUnaryOpImpl + : public internal::generic_xpr_base >::type { - public: - - typedef CwiseUnaryOp Derived; - typedef typename internal::dense_xpr_base >::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(Derived) - - EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const - { - return derived().functor()(derived().nestedExpression().coeff(rowId, colId)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const - { - return derived().functor().packetOp(derived().nestedExpression().template packet(rowId, colId)); - } - - EIGEN_STRONG_INLINE const Scalar coeff(Index index) const - { - return derived().functor()(derived().nestedExpression().coeff(index)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index index) const - { - return derived().functor().packetOp(derived().nestedExpression().template packet(index)); - } +public: + typedef typename internal::generic_xpr_base >::type Base; }; } // end namespace Eigen diff --git a/splinter/src/Core/CwiseUnaryView.h b/splinter/thirdparty/Eigen/Eigen/src/Core/CwiseUnaryView.h similarity index 70% rename from splinter/src/Core/CwiseUnaryView.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/CwiseUnaryView.h index f3b2ffeb6f..2710330562 100644 --- a/splinter/src/Core/CwiseUnaryView.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/CwiseUnaryView.h @@ -12,33 +12,19 @@ namespace Eigen { -/** \class CwiseUnaryView - * \ingroup Core_Module - * - * \brief Generic lvalue expression of a coefficient-wise unary operator of a matrix or a vector - * - * \param ViewOp template functor implementing the view - * \param MatrixType the type of the matrix we are applying the unary operator - * - * This class represents a lvalue expression of a generic unary view operator of a matrix or a vector. - * It is the return type of real() and imag(), and most of the time this is the only way it is used. - * - * \sa MatrixBase::unaryViewExpr(const CustomUnaryOp &) const, class CwiseUnaryOp - */ - namespace internal { template struct traits > : traits { typedef typename result_of< - ViewOp(typename traits::Scalar) + ViewOp(const typename traits::Scalar&) >::type Scalar; typedef typename MatrixType::Nested MatrixTypeNested; typedef typename remove_all::type _MatrixTypeNested; enum { - Flags = (traits<_MatrixTypeNested>::Flags & (HereditaryBits | LvalueBit | LinearAccessBit | DirectAccessBit)), - CoeffReadCost = EIGEN_ADD_COST(traits<_MatrixTypeNested>::CoeffReadCost, functor_traits::Cost), + FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, + Flags = traits<_MatrixTypeNested>::Flags & (RowMajorBit | FlagsLvalueBit | DirectAccessBit), // FIXME DirectAccessBit should not be handled by expressions MatrixTypeInnerStride = inner_stride_at_compile_time::ret, // need to cast the sizeof's from size_t to int explicitly, otherwise: // "error: no integral type can represent all of the enumerator values @@ -55,6 +41,19 @@ struct traits > template class CwiseUnaryViewImpl; +/** \class CwiseUnaryView + * \ingroup Core_Module + * + * \brief Generic lvalue expression of a coefficient-wise unary operator of a matrix or a vector + * + * \tparam ViewOp template functor implementing the view + * \tparam MatrixType the type of the matrix we are applying the unary operator + * + * This class represents a lvalue expression of a generic unary view operator of a matrix or a vector. + * It is the return type of real() and imag(), and most of the time this is the only way it is used. + * + * \sa MatrixBase::unaryViewExpr(const CustomUnaryOp &) const, class CwiseUnaryOp + */ template class CwiseUnaryView : public CwiseUnaryViewImpl::StorageKind> { @@ -62,8 +61,10 @@ class CwiseUnaryView : public CwiseUnaryViewImpl::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryView) + typedef typename internal::ref_selector::non_const_type MatrixTypeNested; + typedef typename internal::remove_all::type NestedExpression; - inline CwiseUnaryView(const MatrixType& mat, const ViewOp& func = ViewOp()) + explicit inline CwiseUnaryView(MatrixType& mat, const ViewOp& func = ViewOp()) : m_matrix(mat), m_functor(func) {} EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryView) @@ -75,19 +76,27 @@ class CwiseUnaryView : public CwiseUnaryViewImpl::type& + const typename internal::remove_all::type& nestedExpression() const { return m_matrix; } /** \returns the nested expression */ - typename internal::remove_all::type& + typename internal::remove_reference::type& nestedExpression() { return m_matrix.const_cast_derived(); } protected: - // FIXME changed from MatrixType::Nested because of a weird compilation error with sun CC - typename internal::nested::type m_matrix; + MatrixTypeNested m_matrix; ViewOp m_functor; }; +// Generic API dispatcher +template +class CwiseUnaryViewImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; +}; + template class CwiseUnaryViewImpl : public internal::dense_xpr_base< CwiseUnaryView >::type @@ -100,38 +109,18 @@ class CwiseUnaryViewImpl EIGEN_DENSE_PUBLIC_INTERFACE(Derived) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryViewImpl) - inline Scalar* data() { return &coeffRef(0); } - inline const Scalar* data() const { return &coeff(0); } + EIGEN_DEVICE_FUNC inline Scalar* data() { return &(this->coeffRef(0)); } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return &(this->coeff(0)); } - inline Index innerStride() const + EIGEN_DEVICE_FUNC inline Index innerStride() const { return derived().nestedExpression().innerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); } - inline Index outerStride() const + EIGEN_DEVICE_FUNC inline Index outerStride() const { return derived().nestedExpression().outerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); } - - EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const - { - return derived().functor()(derived().nestedExpression().coeff(row, col)); - } - - EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const - { - return derived().functor()(derived().nestedExpression().coeff(index)); - } - - EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) - { - return derived().functor()(const_cast_derived().nestedExpression().coeffRef(row, col)); - } - - EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) - { - return derived().functor()(const_cast_derived().nestedExpression().coeffRef(index)); - } }; } // end namespace Eigen diff --git a/splinter/src/Core/DenseBase.h b/splinter/thirdparty/Eigen/Eigen/src/Core/DenseBase.h similarity index 56% rename from splinter/src/Core/DenseBase.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/DenseBase.h index 4b371b075b..90066ae73f 100644 --- a/splinter/src/Core/DenseBase.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/DenseBase.h @@ -34,37 +34,45 @@ static inline void check_DenseIndex_is_signed() { * \tparam Derived is the derived type, e.g., a matrix type or an expression. * * 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_DENSEBASE_PLUGIN. + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_DENSEBASE_PLUGIN. * - * \sa \ref TopicClassHierarchy + * \sa \blank \ref TopicClassHierarchy */ template class DenseBase #ifndef EIGEN_PARSED_BY_DOXYGEN - : public internal::special_scalar_op_base::Scalar, - typename NumTraits::Scalar>::Real, - DenseCoeffsBase > -#else : public DenseCoeffsBase +#else + : public DenseCoeffsBase #endif // not EIGEN_PARSED_BY_DOXYGEN { public: - class InnerIterator; + /** Inner iterator type to iterate over the coefficients of a row or column. + * \sa class InnerIterator + */ + typedef Eigen::InnerIterator InnerIterator; typedef typename internal::traits::StorageKind StorageKind; - /** \brief The type of indices - * \details To change this, \c \#define the preprocessor symbol \c EIGEN_DEFAULT_DENSE_INDEX_TYPE. - * \sa \ref TopicPreprocessorDirectives. - */ - typedef typename internal::traits::Index Index; + /** + * \brief The type used to store indices + * \details This typedef is relevant for types that store multiple indices such as + * PermutationMatrix or Transpositions, otherwise it defaults to Eigen::Index + * \sa \blank \ref TopicPreprocessorDirectives, Eigen::Index, SparseMatrixBase. + */ + typedef typename internal::traits::StorageIndex StorageIndex; + /** The numeric type of the expression' coefficients, e.g. float, double, int or std::complex, etc. */ typedef typename internal::traits::Scalar Scalar; - typedef typename internal::packet_traits::type PacketScalar; + + /** The numeric type of the expression' coefficients, e.g. float, double, int or std::complex, etc. + * + * It is an alias for the Scalar type */ + typedef Scalar value_type; + typedef typename NumTraits::Real RealScalar; - typedef internal::special_scalar_op_base > Base; + typedef DenseCoeffsBase Base; - using Base::operator*; using Base::derived; using Base::const_cast_derived; using Base::rows; @@ -74,16 +82,6 @@ template class DenseBase using Base::colIndexByOuterInner; using Base::coeff; using Base::coeffByOuterInner; - using Base::packet; - using Base::packetByOuterInner; - using Base::writePacket; - using Base::writePacketByOuterInner; - using Base::coeffRef; - using Base::coeffRefByOuterInner; - using Base::copyCoeff; - using Base::copyCoeffByOuterInner; - using Base::copyPacket; - using Base::copyPacketByOuterInner; using Base::operator(); using Base::operator[]; using Base::x; @@ -169,19 +167,46 @@ template class DenseBase InnerSizeAtCompileTime = int(IsVectorAtCompileTime) ? int(SizeAtCompileTime) : int(IsRowMajor) ? int(ColsAtCompileTime) : int(RowsAtCompileTime), - CoeffReadCost = internal::traits::CoeffReadCost, - /**< This is a rough measure of how expensive it is to read one coefficient from - * this expression. - */ - InnerStrideAtCompileTime = internal::inner_stride_at_compile_time::ret, OuterStrideAtCompileTime = internal::outer_stride_at_compile_time::ret }; + + typedef typename internal::find_best_packet::type PacketScalar; - enum { ThisConstantIsPrivateInPlainObjectBase }; + enum { IsPlainObjectBase = 0 }; + + /** The plain matrix type corresponding to this expression. + * \sa PlainObject */ + typedef Matrix::Scalar, + internal::traits::RowsAtCompileTime, + internal::traits::ColsAtCompileTime, + AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), + internal::traits::MaxRowsAtCompileTime, + internal::traits::MaxColsAtCompileTime + > PlainMatrix; + + /** The plain array type corresponding to this expression. + * \sa PlainObject */ + typedef Array::Scalar, + internal::traits::RowsAtCompileTime, + internal::traits::ColsAtCompileTime, + AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), + internal::traits::MaxRowsAtCompileTime, + internal::traits::MaxColsAtCompileTime + > PlainArray; + + /** \brief The plain matrix or array type corresponding to this expression. + * + * This is not necessarily exactly the return type of eval(). In the case of plain matrices, + * the return type of eval() is a const reference to a matrix, not a matrix! It is however guaranteed + * that the return type of eval() is either PlainObject or const PlainObject&. + */ + typedef typename internal::conditional::XprKind,MatrixXpr >::value, + PlainMatrix, PlainArray>::type PlainObject; /** \returns the number of nonzero coefficients which is in practice the number * of stored coefficients. */ + EIGEN_DEVICE_FUNC inline Index nonZeros() const { return size(); } /** \returns the outer size. @@ -189,6 +214,7 @@ template class DenseBase * \note For a vector, this returns just 1. For a matrix (non-vector), this is the major dimension * with respect to the \ref TopicStorageOrders "storage order", i.e., the number of columns for a * column-major matrix, and the number of rows for a row-major matrix. */ + EIGEN_DEVICE_FUNC Index outerSize() const { return IsVectorAtCompileTime ? 1 @@ -200,6 +226,7 @@ template class DenseBase * \note For a vector, this is just the size. For a matrix (non-vector), this is the minor dimension * with respect to the \ref TopicStorageOrders "storage order", i.e., the number of rows for a * column-major matrix, and the number of columns for a row-major matrix. */ + EIGEN_DEVICE_FUNC Index innerSize() const { return IsVectorAtCompileTime ? this->size() @@ -210,6 +237,7 @@ template class DenseBase * Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does * nothing else. */ + EIGEN_DEVICE_FUNC void resize(Index newSize) { EIGEN_ONLY_USED_FOR_DEBUG(newSize); @@ -220,22 +248,22 @@ template class DenseBase * Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does * nothing else. */ - void resize(Index nbRows, Index nbCols) + EIGEN_DEVICE_FUNC + void resize(Index rows, Index cols) { - EIGEN_ONLY_USED_FOR_DEBUG(nbRows); - EIGEN_ONLY_USED_FOR_DEBUG(nbCols); - eigen_assert(nbRows == this->rows() && nbCols == this->cols() + EIGEN_ONLY_USED_FOR_DEBUG(rows); + EIGEN_ONLY_USED_FOR_DEBUG(cols); + eigen_assert(rows == this->rows() && cols == this->cols() && "DenseBase::resize() does not actually allow to resize."); } #ifndef EIGEN_PARSED_BY_DOXYGEN - /** \internal Represents a matrix with all coefficients equal to one another*/ - typedef CwiseNullaryOp,Derived> ConstantReturnType; - /** \internal Represents a vector with linearly spaced coefficients that allows sequential access only. */ - typedef CwiseNullaryOp,Derived> SequentialLinSpacedReturnType; + typedef CwiseNullaryOp,PlainObject> ConstantReturnType; + /** \internal \deprecated Represents a vector with linearly spaced coefficients that allows sequential access only. */ + typedef CwiseNullaryOp,PlainObject> SequentialLinSpacedReturnType; /** \internal Represents a vector with linearly spaced coefficients that allows random access. */ - typedef CwiseNullaryOp,Derived> RandomAccessLinSpacedReturnType; + typedef CwiseNullaryOp,PlainObject> RandomAccessLinSpacedReturnType; /** \internal the return type of MatrixBase::eigenvalues() */ typedef Matrix::Scalar>::Real, internal::traits::ColsAtCompileTime, 1> EigenvaluesReturnType; @@ -243,120 +271,133 @@ template class DenseBase /** Copies \a other into *this. \returns a reference to *this. */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const DenseBase& other); /** Special case of the template operator=, in order to prevent the compiler * from generating a default operator= (issue hit with g++ 4.1) */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const DenseBase& other); template + EIGEN_DEVICE_FUNC Derived& operator=(const EigenBase &other); template + EIGEN_DEVICE_FUNC Derived& operator+=(const EigenBase &other); template + EIGEN_DEVICE_FUNC Derived& operator-=(const EigenBase &other); template + EIGEN_DEVICE_FUNC Derived& operator=(const ReturnByValue& func); - /** \internal Copies \a other into *this without evaluating other. \returns a reference to *this. */ + /** \internal + * Copies \a other into *this without evaluating other. \returns a reference to *this. + * \deprecated */ template + EIGEN_DEVICE_FUNC Derived& lazyAssign(const DenseBase& other); - /** \internal Evaluates \a other into *this. \returns a reference to *this. */ - template - Derived& lazyAssign(const ReturnByValue& other); - + EIGEN_DEVICE_FUNC CommaInitializer operator<< (const Scalar& s); + /** \deprecated it now returns \c *this */ template - const Flagged flagged() const; + EIGEN_DEPRECATED + const Derived& flagged() const + { return derived(); } template + EIGEN_DEVICE_FUNC CommaInitializer operator<< (const DenseBase& other); - Eigen::Transpose transpose(); - typedef typename internal::add_const >::type ConstTransposeReturnType; + typedef Transpose TransposeReturnType; + EIGEN_DEVICE_FUNC + TransposeReturnType transpose(); + typedef typename internal::add_const >::type ConstTransposeReturnType; + EIGEN_DEVICE_FUNC ConstTransposeReturnType transpose() const; + EIGEN_DEVICE_FUNC void transposeInPlace(); -#ifndef EIGEN_NO_DEBUG - protected: - template - void checkTransposeAliasing(const OtherDerived& other) const; - public: -#endif - - static const ConstantReturnType + EIGEN_DEVICE_FUNC static const ConstantReturnType Constant(Index rows, Index cols, const Scalar& value); - static const ConstantReturnType + EIGEN_DEVICE_FUNC static const ConstantReturnType Constant(Index size, const Scalar& value); - static const ConstantReturnType + EIGEN_DEVICE_FUNC static const ConstantReturnType Constant(const Scalar& value); - static const SequentialLinSpacedReturnType + EIGEN_DEVICE_FUNC static const SequentialLinSpacedReturnType LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high); - static const RandomAccessLinSpacedReturnType + EIGEN_DEVICE_FUNC static const RandomAccessLinSpacedReturnType LinSpaced(Index size, const Scalar& low, const Scalar& high); - static const SequentialLinSpacedReturnType + EIGEN_DEVICE_FUNC static const SequentialLinSpacedReturnType LinSpaced(Sequential_t, const Scalar& low, const Scalar& high); - static const RandomAccessLinSpacedReturnType + EIGEN_DEVICE_FUNC static const RandomAccessLinSpacedReturnType LinSpaced(const Scalar& low, const Scalar& high); - template - static const CwiseNullaryOp + template EIGEN_DEVICE_FUNC + static const CwiseNullaryOp NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func); - template - static const CwiseNullaryOp + template EIGEN_DEVICE_FUNC + static const CwiseNullaryOp NullaryExpr(Index size, const CustomNullaryOp& func); - template - static const CwiseNullaryOp + template EIGEN_DEVICE_FUNC + static const CwiseNullaryOp NullaryExpr(const CustomNullaryOp& func); - static const ConstantReturnType Zero(Index rows, Index cols); - static const ConstantReturnType Zero(Index size); - static const ConstantReturnType Zero(); - static const ConstantReturnType Ones(Index rows, Index cols); - static const ConstantReturnType Ones(Index size); - static const ConstantReturnType Ones(); - - void fill(const Scalar& value); - Derived& setConstant(const Scalar& value); - Derived& setLinSpaced(Index size, const Scalar& low, const Scalar& high); - Derived& setLinSpaced(const Scalar& low, const Scalar& high); - Derived& setZero(); - Derived& setOnes(); - Derived& setRandom(); - - template + EIGEN_DEVICE_FUNC static const ConstantReturnType Zero(Index rows, Index cols); + EIGEN_DEVICE_FUNC static const ConstantReturnType Zero(Index size); + EIGEN_DEVICE_FUNC static const ConstantReturnType Zero(); + EIGEN_DEVICE_FUNC static const ConstantReturnType Ones(Index rows, Index cols); + EIGEN_DEVICE_FUNC static const ConstantReturnType Ones(Index size); + EIGEN_DEVICE_FUNC static const ConstantReturnType Ones(); + + EIGEN_DEVICE_FUNC void fill(const Scalar& value); + EIGEN_DEVICE_FUNC Derived& setConstant(const Scalar& value); + EIGEN_DEVICE_FUNC Derived& setLinSpaced(Index size, const Scalar& low, const Scalar& high); + EIGEN_DEVICE_FUNC Derived& setLinSpaced(const Scalar& low, const Scalar& high); + EIGEN_DEVICE_FUNC Derived& setZero(); + EIGEN_DEVICE_FUNC Derived& setOnes(); + EIGEN_DEVICE_FUNC Derived& setRandom(); + + template EIGEN_DEVICE_FUNC bool isApprox(const DenseBase& other, const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isMuchSmallerThan(const RealScalar& other, const RealScalar& prec = NumTraits::dummy_precision()) const; - template + template EIGEN_DEVICE_FUNC bool isMuchSmallerThan(const DenseBase& other, const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isApproxToConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isZero(const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isOnes(const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isApproxToConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isZero(const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isOnes(const RealScalar& prec = NumTraits::dummy_precision()) const; inline bool hasNaN() const; inline bool allFinite() const; - inline Derived& operator*=(const Scalar& other); - inline Derived& operator/=(const Scalar& other); + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator*=(const Scalar& other); + EIGEN_DEVICE_FUNC EIGEN_STRONG_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. + * + * \warning Be carefull with eval() and the auto C++ keyword, as detailed in this \link TopicPitfalls_auto_keyword page \endlink. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EvalReturnType eval() const { // Even though MSVC does not honor strong inlining when the return type @@ -364,61 +405,78 @@ template class DenseBase // size types on MSVC. return typename internal::eval::type(derived()); } - + /** swaps *this with the expression \a other. * */ template - void swap(const DenseBase& other, - int = OtherDerived::ThisConstantIsPrivateInPlainObjectBase) + EIGEN_DEVICE_FUNC + void swap(const DenseBase& other) { - SwapWrapper(derived()).lazyAssign(other.derived()); + EIGEN_STATIC_ASSERT(!OtherDerived::IsPlainObjectBase,THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); + eigen_assert(rows()==other.rows() && cols()==other.cols()); + call_assignment(derived(), other.const_cast_derived(), internal::swap_assign_op()); } /** swaps *this with the matrix or array \a other. * */ template + EIGEN_DEVICE_FUNC void swap(PlainObjectBase& other) { - SwapWrapper(derived()).lazyAssign(other.derived()); + eigen_assert(rows()==other.rows() && cols()==other.cols()); + call_assignment(derived(), other.derived(), internal::swap_assign_op()); } + EIGEN_DEVICE_FUNC inline const NestByValue nestByValue() const; + EIGEN_DEVICE_FUNC inline const ForceAlignedAccess forceAlignedAccess() const; + EIGEN_DEVICE_FUNC inline ForceAlignedAccess forceAlignedAccess(); + template EIGEN_DEVICE_FUNC + inline const typename internal::conditional,Derived&>::type forceAlignedAccessIf() const; + template EIGEN_DEVICE_FUNC + inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); - inline const NestByValue nestByValue() const; - inline const ForceAlignedAccess forceAlignedAccess() const; - inline ForceAlignedAccess forceAlignedAccess(); - template inline const typename internal::conditional,Derived&>::type forceAlignedAccessIf() const; - template inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); - - Scalar sum() const; - Scalar mean() const; - Scalar trace() const; + EIGEN_DEVICE_FUNC Scalar sum() const; + EIGEN_DEVICE_FUNC Scalar mean() const; + EIGEN_DEVICE_FUNC Scalar trace() const; - Scalar prod() const; + EIGEN_DEVICE_FUNC Scalar prod() const; - typename internal::traits::Scalar minCoeff() const; - typename internal::traits::Scalar maxCoeff() const; + EIGEN_DEVICE_FUNC typename internal::traits::Scalar minCoeff() const; + EIGEN_DEVICE_FUNC typename internal::traits::Scalar maxCoeff() const; - template + template EIGEN_DEVICE_FUNC typename internal::traits::Scalar minCoeff(IndexType* row, IndexType* col) const; - template + template EIGEN_DEVICE_FUNC typename internal::traits::Scalar maxCoeff(IndexType* row, IndexType* col) const; - template + template EIGEN_DEVICE_FUNC typename internal::traits::Scalar minCoeff(IndexType* index) const; - template + template EIGEN_DEVICE_FUNC typename internal::traits::Scalar maxCoeff(IndexType* index) const; template - typename internal::result_of::Scalar)>::type - redux(const BinaryOp& func) const; + EIGEN_DEVICE_FUNC + Scalar redux(const BinaryOp& func) const; template + EIGEN_DEVICE_FUNC void visit(Visitor& func) const; - inline const WithFormat format(const IOFormat& fmt) const; + /** \returns a WithFormat proxy object allowing to print a matrix the with given + * format \a fmt. + * + * See class IOFormat for some examples. + * + * \sa class IOFormat, class WithFormat + */ + inline const WithFormat format(const IOFormat& fmt) const + { + return WithFormat(derived(), fmt); + } /** \returns the unique coefficient of a 1x1 expression */ + EIGEN_DEVICE_FUNC CoeffReturnType value() const { EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) @@ -426,23 +484,44 @@ template class DenseBase return derived().coeff(0,0); } - bool all(void) const; - bool any(void) const; - Index count() const; + EIGEN_DEVICE_FUNC bool all() const; + EIGEN_DEVICE_FUNC bool any() const; + EIGEN_DEVICE_FUNC Index count() const; typedef VectorwiseOp RowwiseReturnType; typedef const VectorwiseOp ConstRowwiseReturnType; typedef VectorwiseOp ColwiseReturnType; typedef const VectorwiseOp ConstColwiseReturnType; - ConstRowwiseReturnType rowwise() const; - RowwiseReturnType rowwise(); - ConstColwiseReturnType colwise() const; - ColwiseReturnType colwise(); + /** \returns a VectorwiseOp wrapper of *this providing additional partial reduction operations + * + * Example: \include MatrixBase_rowwise.cpp + * Output: \verbinclude MatrixBase_rowwise.out + * + * \sa colwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting + */ + //Code moved here due to a CUDA compiler bug + EIGEN_DEVICE_FUNC inline ConstRowwiseReturnType rowwise() const { + return ConstRowwiseReturnType(derived()); + } + EIGEN_DEVICE_FUNC RowwiseReturnType rowwise(); + + /** \returns a VectorwiseOp wrapper of *this providing additional partial reduction operations + * + * Example: \include MatrixBase_colwise.cpp + * Output: \verbinclude MatrixBase_colwise.out + * + * \sa rowwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting + */ + EIGEN_DEVICE_FUNC inline ConstColwiseReturnType colwise() const { + return ConstColwiseReturnType(derived()); + } + EIGEN_DEVICE_FUNC ColwiseReturnType colwise(); - static const CwiseNullaryOp,Derived> Random(Index rows, Index cols); - static const CwiseNullaryOp,Derived> Random(Index size); - static const CwiseNullaryOp,Derived> Random(); + typedef CwiseNullaryOp,PlainObject> RandomReturnType; + static const RandomReturnType Random(Index rows, Index cols); + static const RandomReturnType Random(Index size); + static const RandomReturnType Random(); template const Select @@ -460,45 +539,56 @@ template class DenseBase template RealScalar lpNorm() const; template - inline const Replicate replicate() const; - - typedef Replicate ReplicateReturnType; - inline const ReplicateReturnType replicate(Index rowFacor,Index colFactor) const; + EIGEN_DEVICE_FUNC + const Replicate replicate() const; + /** + * \return an expression of the replication of \c *this + * + * Example: \include MatrixBase_replicate_int_int.cpp + * Output: \verbinclude MatrixBase_replicate_int_int.out + * + * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate + */ + //Code moved here due to a CUDA compiler bug + EIGEN_DEVICE_FUNC + const Replicate replicate(Index rowFactor, Index colFactor) const + { + return Replicate(derived(), rowFactor, colFactor); + } typedef Reverse ReverseReturnType; typedef const Reverse ConstReverseReturnType; - ReverseReturnType reverse(); - ConstReverseReturnType reverse() const; - void reverseInPlace(); + EIGEN_DEVICE_FUNC ReverseReturnType reverse(); + /** This is the const version of reverse(). */ + //Code moved here due to a CUDA compiler bug + EIGEN_DEVICE_FUNC ConstReverseReturnType reverse() const + { + return ConstReverseReturnType(derived()); + } + EIGEN_DEVICE_FUNC void reverseInPlace(); #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::DenseBase +#define EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +#define EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(COND) # include "../plugins/BlockMethods.h" # ifdef EIGEN_DENSEBASE_PLUGIN # include EIGEN_DENSEBASE_PLUGIN # endif #undef EIGEN_CURRENT_STORAGE_BASE_CLASS - -#ifdef EIGEN2_SUPPORT - - Block corner(CornerType type, Index cRows, Index cCols); - const Block corner(CornerType type, Index cRows, Index cCols) const; - template - Block corner(CornerType type); - template - const Block corner(CornerType type) const; - -#endif // EIGEN2_SUPPORT - +#undef EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +#undef EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF // disable the use of evalTo for dense objects with a nice compilation error - template inline void evalTo(Dest& ) const + template + EIGEN_DEVICE_FUNC + inline void evalTo(Dest& ) const { EIGEN_STATIC_ASSERT((internal::is_same::value),THE_EVAL_EVALTO_FUNCTION_SHOULD_NEVER_BE_CALLED_FOR_DENSE_OBJECTS); } protected: /** Default constructor. Do nothing. */ - DenseBase() + EIGEN_DEVICE_FUNC DenseBase() { /* Just checks for self-consistency of the flags. * Only do it when debugging Eigen, as this borders on paranoiac and could slow compilation down @@ -511,9 +601,9 @@ template class DenseBase } private: - explicit DenseBase(int); - DenseBase(int,int); - template explicit DenseBase(const DenseBase&); + EIGEN_DEVICE_FUNC explicit DenseBase(int); + EIGEN_DEVICE_FUNC DenseBase(int,int); + template EIGEN_DEVICE_FUNC explicit DenseBase(const DenseBase&); }; } // end namespace Eigen diff --git a/splinter/src/Core/DenseCoeffsBase.h b/splinter/thirdparty/Eigen/Eigen/src/Core/DenseCoeffsBase.h similarity index 72% rename from splinter/src/Core/DenseCoeffsBase.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/DenseCoeffsBase.h index 3c890f2159..c4af48ab69 100644 --- a/splinter/src/Core/DenseCoeffsBase.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/DenseCoeffsBase.h @@ -35,7 +35,6 @@ class DenseCoeffsBase : public EigenBase { public: typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; @@ -61,6 +60,7 @@ class DenseCoeffsBase : public EigenBase using Base::size; using Base::derived; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner) const { return int(Derived::RowsAtCompileTime) == 1 ? 0 @@ -69,6 +69,7 @@ class DenseCoeffsBase : public EigenBase : inner; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index colIndexByOuterInner(Index outer, Index inner) const { return int(Derived::ColsAtCompileTime) == 1 ? 0 @@ -91,13 +92,15 @@ class DenseCoeffsBase : public EigenBase * * \sa operator()(Index,Index) const, coeffRef(Index,Index), coeff(Index) const */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - return derived().coeff(row, col); + && col >= 0 && col < cols()); + return internal::evaluator(derived()).coeff(row,col); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeffByOuterInner(Index outer, Index inner) const { return coeff(rowIndexByOuterInner(outer, inner), @@ -108,11 +111,12 @@ class DenseCoeffsBase : public EigenBase * * \sa operator()(Index,Index), operator[](Index) */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType operator()(Index row, Index col) const { eigen_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); - return derived().coeff(row, col); + return coeff(row, col); } /** Short version: don't use this function, use @@ -130,11 +134,14 @@ class DenseCoeffsBase : public EigenBase * \sa operator[](Index) const, coeffRef(Index), coeff(Index,Index) const */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { + EIGEN_STATIC_ASSERT(internal::evaluator::Flags & LinearAccessBit, + THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS) eigen_internal_assert(index >= 0 && index < size()); - return derived().coeff(index); + return internal::evaluator(derived()).coeff(index); } @@ -146,15 +153,14 @@ class DenseCoeffsBase : public EigenBase * z() const, w() const */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType operator[](Index index) const { - #ifndef EIGEN2_SUPPORT EIGEN_STATIC_ASSERT(Derived::IsVectorAtCompileTime, THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD) - #endif eigen_assert(index >= 0 && index < size()); - return derived().coeff(index); + return coeff(index); } /** \returns the coefficient at given index. @@ -167,32 +173,49 @@ class DenseCoeffsBase : public EigenBase * z() const, w() const */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType operator()(Index index) const { eigen_assert(index >= 0 && index < size()); - return derived().coeff(index); + return coeff(index); } /** equivalent to operator[](0). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType x() const { return (*this)[0]; } /** equivalent to operator[](1). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType - y() const { return (*this)[1]; } + y() const + { + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=2, OUT_OF_RANGE_ACCESS); + return (*this)[1]; + } /** equivalent to operator[](2). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType - z() const { return (*this)[2]; } + z() const + { + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=3, OUT_OF_RANGE_ACCESS); + return (*this)[2]; + } /** equivalent to operator[](3). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType - w() const { return (*this)[3]; } + w() const + { + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=4, OUT_OF_RANGE_ACCESS); + return (*this)[3]; + } /** \internal * \returns the packet of coefficients starting at the given row and column. It is your responsibility @@ -207,9 +230,9 @@ class DenseCoeffsBase : public EigenBase template EIGEN_STRONG_INLINE PacketReturnType packet(Index row, Index col) const { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - return derived().template packet(row,col); + typedef typename internal::packet_traits::type DefaultPacketType; + eigen_internal_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); + return internal::evaluator(derived()).template packet(row,col); } @@ -234,8 +257,11 @@ class DenseCoeffsBase : public EigenBase template EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const { + EIGEN_STATIC_ASSERT(internal::evaluator::Flags & LinearAccessBit, + THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS) + typedef typename internal::packet_traits::type DefaultPacketType; eigen_internal_assert(index >= 0 && index < size()); - return derived().template packet(index); + return internal::evaluator(derived()).template packet(index); } protected: @@ -278,7 +304,6 @@ class DenseCoeffsBase : public DenseCoeffsBase Base; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; @@ -311,13 +336,15 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && row < rows() - && col >= 0 && col < cols()); - return derived().coeffRef(row, col); + && col >= 0 && col < cols()); + return internal::evaluator(derived()).coeffRef(row,col); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRefByOuterInner(Index outer, Index inner) { @@ -330,12 +357,13 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && row < rows() && col >= 0 && col < cols()); - return derived().coeffRef(row, col); + return coeffRef(row, col); } @@ -354,11 +382,14 @@ class DenseCoeffsBase : public DenseCoeffsBase::Flags & LinearAccessBit, + THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS) eigen_internal_assert(index >= 0 && index < size()); - return derived().coeffRef(index); + return internal::evaluator(derived()).coeffRef(index); } /** \returns a reference to the coefficient at given index. @@ -368,15 +399,14 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && index < size()); - return derived().coeffRef(index); + return coeffRef(index); } /** \returns a reference to the coefficient at given index. @@ -388,167 +418,49 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && index < size()); - return derived().coeffRef(index); + return coeffRef(index); } /** equivalent to operator[](0). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& x() { return (*this)[0]; } /** equivalent to operator[](1). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& - y() { return (*this)[1]; } - - /** equivalent to operator[](2). */ - - EIGEN_STRONG_INLINE Scalar& - z() { return (*this)[2]; } - - /** equivalent to operator[](3). */ - - EIGEN_STRONG_INLINE Scalar& - w() { return (*this)[3]; } - - /** \internal - * Stores the given packet of coefficients, at the given row and column of this expression. It is your responsibility - * to ensure that a packet really starts there. This method is only available on expressions having the - * PacketAccessBit. - * - * The \a LoadMode parameter may have the value \a #Aligned or \a #Unaligned. Its effect is to select - * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets - * starting at an address which is a multiple of the packet size. - */ - - template - EIGEN_STRONG_INLINE void writePacket - (Index row, Index col, const typename internal::packet_traits::type& val) + y() { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - derived().template writePacket(row,col,val); + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=2, OUT_OF_RANGE_ACCESS); + return (*this)[1]; } + /** equivalent to operator[](2). */ - /** \internal */ - template - EIGEN_STRONG_INLINE void writePacketByOuterInner - (Index outer, Index inner, const typename internal::packet_traits::type& val) - { - writePacket(rowIndexByOuterInner(outer, inner), - colIndexByOuterInner(outer, inner), - val); - } - - /** \internal - * Stores the given packet of coefficients, at the given index in this expression. It is your responsibility - * to ensure that a packet really starts there. This method is only available on expressions having the - * PacketAccessBit and the LinearAccessBit. - * - * The \a LoadMode parameter may have the value \a Aligned or \a Unaligned. Its effect is to select - * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets - * starting at an address which is a multiple of the packet size. - */ - template - EIGEN_STRONG_INLINE void writePacket - (Index index, const typename internal::packet_traits::type& val) - { - eigen_internal_assert(index >= 0 && index < size()); - derived().template writePacket(index,val); - } - -#ifndef EIGEN_PARSED_BY_DOXYGEN - - /** \internal Copies the coefficient at position (row,col) of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyCoeff(Index row, Index col, const DenseBase& other) - { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - derived().coeffRef(row, col) = other.derived().coeff(row, col); - } - - /** \internal Copies the coefficient at the given index of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyCoeff(Index index, const DenseBase& other) - { - eigen_internal_assert(index >= 0 && index < size()); - derived().coeffRef(index) = other.derived().coeff(index); - } - - - template - EIGEN_STRONG_INLINE void copyCoeffByOuterInner(Index outer, Index inner, const DenseBase& other) - { - const Index row = rowIndexByOuterInner(outer,inner); - const Index col = colIndexByOuterInner(outer,inner); - // derived() is important here: copyCoeff() may be reimplemented in Derived! - derived().copyCoeff(row, col, other); - } - - /** \internal Copies the packet at position (row,col) of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyPacket(Index row, Index col, const DenseBase& other) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& + z() { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - derived().template writePacket(row, col, - other.derived().template packet(row, col)); + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=3, OUT_OF_RANGE_ACCESS); + return (*this)[2]; } - /** \internal Copies the packet at the given index of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyPacket(Index index, const DenseBase& other) - { - eigen_internal_assert(index >= 0 && index < size()); - derived().template writePacket(index, - other.derived().template packet(index)); - } + /** equivalent to operator[](3). */ - /** \internal */ - template - EIGEN_STRONG_INLINE void copyPacketByOuterInner(Index outer, Index inner, const DenseBase& other) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& + w() { - const Index row = rowIndexByOuterInner(outer,inner); - const Index col = colIndexByOuterInner(outer,inner); - // derived() is important here: copyCoeff() may be reimplemented in Derived! - derived().template copyPacket< OtherDerived, StoreMode, LoadMode>(row, col, other); + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=4, OUT_OF_RANGE_ACCESS); + return (*this)[3]; } -#endif - }; /** \brief Base class providing direct read-only coefficient access to matrices and arrays. @@ -560,7 +472,7 @@ class DenseCoeffsBase : public DenseCoeffsBase which defines functions to access entries read-only using * \c operator() . * - * \sa \ref TopicClassHierarchy + * \sa \blank \ref TopicClassHierarchy */ template class DenseCoeffsBase : public DenseCoeffsBase @@ -568,7 +480,6 @@ class DenseCoeffsBase : public DenseCoeffsBase Base; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename NumTraits::Real RealScalar; @@ -581,6 +492,7 @@ class DenseCoeffsBase : public DenseCoeffsBase : public DenseCoeffsBase : public DenseCoeffsBase : public DenseCoeffsBase : public DenseCoeffsBase which defines functions to access entries read/write using * \c operator(). * - * \sa \ref TopicClassHierarchy + * \sa \blank \ref TopicClassHierarchy */ template class DenseCoeffsBase @@ -639,7 +554,6 @@ class DenseCoeffsBase public: typedef DenseCoeffsBase Base; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename NumTraits::Real RealScalar; @@ -652,6 +566,7 @@ class DenseCoeffsBase * * \sa outerStride(), rowStride(), colStride() */ + EIGEN_DEVICE_FUNC inline Index innerStride() const { return derived().innerStride(); @@ -662,6 +577,7 @@ class DenseCoeffsBase * * \sa innerStride(), rowStride(), colStride() */ + EIGEN_DEVICE_FUNC inline Index outerStride() const { return derived().outerStride(); @@ -677,6 +593,7 @@ class DenseCoeffsBase * * \sa innerStride(), outerStride(), colStride() */ + EIGEN_DEVICE_FUNC inline Index rowStride() const { return Derived::IsRowMajor ? outerStride() : innerStride(); @@ -686,6 +603,7 @@ class DenseCoeffsBase * * \sa innerStride(), outerStride(), rowStride() */ + EIGEN_DEVICE_FUNC inline Index colStride() const { return Derived::IsRowMajor ? innerStride() : outerStride(); @@ -694,33 +612,42 @@ class DenseCoeffsBase namespace internal { -template +template struct first_aligned_impl { - static inline typename Derived::Index run(const Derived&) + static inline Index run(const Derived&) { return 0; } }; -template -struct first_aligned_impl +template +struct first_aligned_impl { - static inline typename Derived::Index run(const Derived& m) + static inline Index run(const Derived& m) { - return internal::first_aligned(&m.const_cast_derived().coeffRef(0,0), m.size()); + return internal::first_aligned(m.data(), m.size()); } }; -/** \internal \returns the index of the first element of the array that is well aligned for vectorization. +/** \internal \returns the index of the first element of the array stored by \a m that is properly aligned with respect to \a Alignment for vectorization. + * + * \tparam Alignment requested alignment in Bytes. * * There is also the variant first_aligned(const Scalar*, Integer) defined in Memory.h. See it for more * documentation. */ +template +static inline Index first_aligned(const DenseBase& m) +{ + enum { ReturnZero = (int(evaluator::Alignment) >= Alignment) || !(Derived::Flags & DirectAccessBit) }; + return first_aligned_impl::run(m.derived()); +} + template -static inline typename Derived::Index first_aligned(const Derived& m) +static inline Index first_default_aligned(const DenseBase& m) { - return first_aligned_impl - - ::run(m); + typedef typename Derived::Scalar Scalar; + typedef typename packet_traits::type DefaultPacketType; + return internal::first_aligned::alignment),Derived>(m); } template::ret> diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/DenseStorage.h b/splinter/thirdparty/Eigen/Eigen/src/Core/DenseStorage.h new file mode 100644 index 0000000000..7958feeb9c --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/DenseStorage.h @@ -0,0 +1,570 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2006-2009 Benoit Jacob +// Copyright (C) 2010-2013 Hauke Heibel +// +// 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 + +#ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN + #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(X) X; EIGEN_DENSE_STORAGE_CTOR_PLUGIN; +#else + #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(X) +#endif + +namespace Eigen { + +namespace internal { + +struct constructor_without_unaligned_array_assert {}; + +template +EIGEN_DEVICE_FUNC +void check_static_allocation_size() +{ + // if EIGEN_STACK_ALLOCATION_LIMIT is defined to 0, then no limit + #if EIGEN_STACK_ALLOCATION_LIMIT + EIGEN_STATIC_ASSERT(Size * sizeof(T) <= EIGEN_STACK_ALLOCATION_LIMIT, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); + #endif +} + +/** \internal + * Static array. If the MatrixOrArrayOptions require auto-alignment, the array will be automatically aligned: + * to 16 bytes boundary if the total size is a multiple of 16 bytes. + */ +template ::value > +struct plain_array +{ + T array[Size]; + + EIGEN_DEVICE_FUNC + plain_array() + { + check_static_allocation_size(); + } + + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + +#if defined(EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT) + #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) +#elif EIGEN_GNUC_AT_LEAST(4,7) + // GCC 4.7 is too aggressive in its optimizations and remove the alignement test based on the fact the array is declared to be aligned. + // See this bug report: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53900 + // Hiding the origin of the array pointer behind a function argument seems to do the trick even if the function is inlined: + template + EIGEN_ALWAYS_INLINE PtrType eigen_unaligned_array_assert_workaround_gcc47(PtrType array) { return array; } + #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ + eigen_assert((internal::UIntPtr(eigen_unaligned_array_assert_workaround_gcc47(array)) & (sizemask)) == 0 \ + && "this assertion is explained here: " \ + "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ + " **** READ THIS WEB PAGE !!! ****"); +#else + #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ + eigen_assert((internal::UIntPtr(array) & (sizemask)) == 0 \ + && "this assertion is explained here: " \ + "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ + " **** READ THIS WEB PAGE !!! ****"); +#endif + +template +struct plain_array +{ + EIGEN_ALIGN_TO_BOUNDARY(8) T array[Size]; + + EIGEN_DEVICE_FUNC + plain_array() + { + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(7); + check_static_allocation_size(); + } + + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + +template +struct plain_array +{ + EIGEN_ALIGN_TO_BOUNDARY(16) T array[Size]; + + EIGEN_DEVICE_FUNC + plain_array() + { + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(15); + check_static_allocation_size(); + } + + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + +template +struct plain_array +{ + EIGEN_ALIGN_TO_BOUNDARY(32) T array[Size]; + + EIGEN_DEVICE_FUNC + plain_array() + { + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(31); + check_static_allocation_size(); + } + + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + +template +struct plain_array +{ + EIGEN_ALIGN_TO_BOUNDARY(64) T array[Size]; + + EIGEN_DEVICE_FUNC + plain_array() + { + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(63); + check_static_allocation_size(); + } + + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + +template +struct plain_array +{ + T array[1]; + EIGEN_DEVICE_FUNC plain_array() {} + EIGEN_DEVICE_FUNC plain_array(constructor_without_unaligned_array_assert) {} +}; + +} // end namespace internal + +/** \internal + * + * \class DenseStorage + * \ingroup Core_Module + * + * \brief Stores the data of a matrix + * + * This class stores the data of fixed-size, dynamic-size or mixed matrices + * in a way as compact as possible. + * + * \sa Matrix + */ +template class DenseStorage; + +// purely fixed-size matrix +template class DenseStorage +{ + internal::plain_array m_data; + public: + EIGEN_DEVICE_FUNC DenseStorage() { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = Size) + } + EIGEN_DEVICE_FUNC + explicit DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(internal::constructor_without_unaligned_array_assert()) {} + EIGEN_DEVICE_FUNC + DenseStorage(const DenseStorage& other) : m_data(other.m_data) { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = Size) + } + EIGEN_DEVICE_FUNC + DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) m_data = other.m_data; + return *this; + } + EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + eigen_internal_assert(size==rows*cols && rows==_Rows && cols==_Cols); + EIGEN_UNUSED_VARIABLE(size); + EIGEN_UNUSED_VARIABLE(rows); + EIGEN_UNUSED_VARIABLE(cols); + } + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); } + EIGEN_DEVICE_FUNC static Index rows(void) {return _Rows;} + EIGEN_DEVICE_FUNC static Index cols(void) {return _Cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index,Index,Index) {} + EIGEN_DEVICE_FUNC void resize(Index,Index,Index) {} + EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } + EIGEN_DEVICE_FUNC T *data() { return m_data.array; } +}; + +// null matrix +template class DenseStorage +{ + public: + EIGEN_DEVICE_FUNC DenseStorage() {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) {} + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage&) {} + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage&) { return *this; } + EIGEN_DEVICE_FUNC DenseStorage(Index,Index,Index) {} + EIGEN_DEVICE_FUNC void swap(DenseStorage& ) {} + EIGEN_DEVICE_FUNC static Index rows(void) {return _Rows;} + EIGEN_DEVICE_FUNC static Index cols(void) {return _Cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index,Index,Index) {} + EIGEN_DEVICE_FUNC void resize(Index,Index,Index) {} + EIGEN_DEVICE_FUNC const T *data() const { return 0; } + EIGEN_DEVICE_FUNC T *data() { return 0; } +}; + +// more specializations for null matrices; these are necessary to resolve ambiguities +template class DenseStorage +: public DenseStorage { }; + +template class DenseStorage +: public DenseStorage { }; + +template class DenseStorage +: public DenseStorage { }; + +// dynamic-size matrix with fixed-size storage +template class DenseStorage +{ + internal::plain_array m_data; + Index m_rows; + Index m_cols; + public: + EIGEN_DEVICE_FUNC DenseStorage() : m_rows(0), m_cols(0) {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0), m_cols(0) {} + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows), m_cols(other.m_cols) {} + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + m_data = other.m_data; + m_rows = other.m_rows; + m_cols = other.m_cols; + } + return *this; + } + EIGEN_DEVICE_FUNC DenseStorage(Index, Index rows, Index cols) : m_rows(rows), m_cols(cols) {} + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) + { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } + EIGEN_DEVICE_FUNC Index rows() const {return m_rows;} + EIGEN_DEVICE_FUNC Index cols() const {return m_cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index, Index rows, Index cols) { m_rows = rows; m_cols = cols; } + EIGEN_DEVICE_FUNC void resize(Index, Index rows, Index cols) { m_rows = rows; m_cols = cols; } + EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } + EIGEN_DEVICE_FUNC T *data() { return m_data.array; } +}; + +// dynamic-size matrix with fixed-size storage and fixed width +template class DenseStorage +{ + internal::plain_array m_data; + Index m_rows; + public: + EIGEN_DEVICE_FUNC DenseStorage() : m_rows(0) {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0) {} + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows) {} + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + m_data = other.m_data; + m_rows = other.m_rows; + } + return *this; + } + EIGEN_DEVICE_FUNC DenseStorage(Index, Index rows, Index) : m_rows(rows) {} + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } + EIGEN_DEVICE_FUNC Index rows(void) const {return m_rows;} + EIGEN_DEVICE_FUNC Index cols(void) const {return _Cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index, Index rows, Index) { m_rows = rows; } + EIGEN_DEVICE_FUNC void resize(Index, Index rows, Index) { m_rows = rows; } + EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } + EIGEN_DEVICE_FUNC T *data() { return m_data.array; } +}; + +// dynamic-size matrix with fixed-size storage and fixed height +template class DenseStorage +{ + internal::plain_array m_data; + Index m_cols; + public: + EIGEN_DEVICE_FUNC DenseStorage() : m_cols(0) {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(internal::constructor_without_unaligned_array_assert()), m_cols(0) {} + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_cols(other.m_cols) {} + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + m_data = other.m_data; + m_cols = other.m_cols; + } + return *this; + } + EIGEN_DEVICE_FUNC DenseStorage(Index, Index, Index cols) : m_cols(cols) {} + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } + EIGEN_DEVICE_FUNC Index rows(void) const {return _Rows;} + EIGEN_DEVICE_FUNC Index cols(void) const {return m_cols;} + void conservativeResize(Index, Index, Index cols) { m_cols = cols; } + void resize(Index, Index, Index cols) { m_cols = cols; } + EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } + EIGEN_DEVICE_FUNC T *data() { return m_data.array; } +}; + +// purely dynamic matrix. +template class DenseStorage +{ + T *m_data; + Index m_rows; + Index m_cols; + public: + EIGEN_DEVICE_FUNC DenseStorage() : m_data(0), m_rows(0), m_cols(0) {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(0), m_rows(0), m_cols(0) {} + EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) + : m_data(internal::conditional_aligned_new_auto(size)), m_rows(rows), m_cols(cols) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + eigen_internal_assert(size==rows*cols && rows>=0 && cols >=0); + } + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) + : m_data(internal::conditional_aligned_new_auto(other.m_rows*other.m_cols)) + , m_rows(other.m_rows) + , m_cols(other.m_cols) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = m_rows*m_cols) + internal::smart_copy(other.m_data, other.m_data+other.m_rows*other.m_cols, m_data); + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + DenseStorage tmp(other); + this->swap(tmp); + } + return *this; + } +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + DenseStorage(DenseStorage&& other) EIGEN_NOEXCEPT + : m_data(std::move(other.m_data)) + , m_rows(std::move(other.m_rows)) + , m_cols(std::move(other.m_cols)) + { + other.m_data = nullptr; + other.m_rows = 0; + other.m_cols = 0; + } + EIGEN_DEVICE_FUNC + DenseStorage& operator=(DenseStorage&& other) EIGEN_NOEXCEPT + { + using std::swap; + swap(m_data, other.m_data); + swap(m_rows, other.m_rows); + swap(m_cols, other.m_cols); + return *this; + } +#endif + EIGEN_DEVICE_FUNC ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); } + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) + { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } + EIGEN_DEVICE_FUNC Index rows(void) const {return m_rows;} + EIGEN_DEVICE_FUNC Index cols(void) const {return m_cols;} + void conservativeResize(Index size, Index rows, Index cols) + { + m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*m_cols); + m_rows = rows; + m_cols = cols; + } + EIGEN_DEVICE_FUNC void resize(Index size, Index rows, Index cols) + { + if(size != m_rows*m_cols) + { + internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); + if (size) + m_data = internal::conditional_aligned_new_auto(size); + else + m_data = 0; + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + } + m_rows = rows; + m_cols = cols; + } + EIGEN_DEVICE_FUNC const T *data() const { return m_data; } + EIGEN_DEVICE_FUNC T *data() { return m_data; } +}; + +// matrix with dynamic width and fixed height (so that matrix has dynamic size). +template class DenseStorage +{ + T *m_data; + Index m_cols; + public: + EIGEN_DEVICE_FUNC DenseStorage() : m_data(0), m_cols(0) {} + explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {} + EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) : m_data(internal::conditional_aligned_new_auto(size)), m_cols(cols) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + eigen_internal_assert(size==rows*cols && rows==_Rows && cols >=0); + EIGEN_UNUSED_VARIABLE(rows); + } + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) + : m_data(internal::conditional_aligned_new_auto(_Rows*other.m_cols)) + , m_cols(other.m_cols) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = m_cols*_Rows) + internal::smart_copy(other.m_data, other.m_data+_Rows*m_cols, m_data); + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + DenseStorage tmp(other); + this->swap(tmp); + } + return *this; + } +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + DenseStorage(DenseStorage&& other) EIGEN_NOEXCEPT + : m_data(std::move(other.m_data)) + , m_cols(std::move(other.m_cols)) + { + other.m_data = nullptr; + other.m_cols = 0; + } + EIGEN_DEVICE_FUNC + DenseStorage& operator=(DenseStorage&& other) EIGEN_NOEXCEPT + { + using std::swap; + swap(m_data, other.m_data); + swap(m_cols, other.m_cols); + return *this; + } +#endif + EIGEN_DEVICE_FUNC ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); } + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } + EIGEN_DEVICE_FUNC static Index rows(void) {return _Rows;} + EIGEN_DEVICE_FUNC Index cols(void) const {return m_cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index size, Index, Index cols) + { + m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, _Rows*m_cols); + m_cols = cols; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize(Index size, Index, Index cols) + { + if(size != _Rows*m_cols) + { + internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); + if (size) + m_data = internal::conditional_aligned_new_auto(size); + else + m_data = 0; + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + } + m_cols = cols; + } + EIGEN_DEVICE_FUNC const T *data() const { return m_data; } + EIGEN_DEVICE_FUNC T *data() { return m_data; } +}; + +// matrix with dynamic height and fixed width (so that matrix has dynamic size). +template class DenseStorage +{ + T *m_data; + Index m_rows; + public: + EIGEN_DEVICE_FUNC DenseStorage() : m_data(0), m_rows(0) {} + explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {} + EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) : m_data(internal::conditional_aligned_new_auto(size)), m_rows(rows) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + eigen_internal_assert(size==rows*cols && rows>=0 && cols == _Cols); + EIGEN_UNUSED_VARIABLE(cols); + } + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) + : m_data(internal::conditional_aligned_new_auto(other.m_rows*_Cols)) + , m_rows(other.m_rows) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = m_rows*_Cols) + internal::smart_copy(other.m_data, other.m_data+other.m_rows*_Cols, m_data); + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + DenseStorage tmp(other); + this->swap(tmp); + } + return *this; + } +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + DenseStorage(DenseStorage&& other) EIGEN_NOEXCEPT + : m_data(std::move(other.m_data)) + , m_rows(std::move(other.m_rows)) + { + other.m_data = nullptr; + other.m_rows = 0; + } + EIGEN_DEVICE_FUNC + DenseStorage& operator=(DenseStorage&& other) EIGEN_NOEXCEPT + { + using std::swap; + swap(m_data, other.m_data); + swap(m_rows, other.m_rows); + return *this; + } +#endif + EIGEN_DEVICE_FUNC ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); } + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } + EIGEN_DEVICE_FUNC Index rows(void) const {return m_rows;} + EIGEN_DEVICE_FUNC static Index cols(void) {return _Cols;} + void conservativeResize(Index size, Index rows, Index) + { + m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*_Cols); + m_rows = rows; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize(Index size, Index rows, Index) + { + if(size != m_rows*_Cols) + { + internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); + if (size) + m_data = internal::conditional_aligned_new_auto(size); + else + m_data = 0; + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + } + m_rows = rows; + } + EIGEN_DEVICE_FUNC const T *data() const { return m_data; } + EIGEN_DEVICE_FUNC T *data() { return m_data; } +}; + +} // end namespace Eigen + +#endif // EIGEN_MATRIX_H diff --git a/splinter/src/Core/Diagonal.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Diagonal.h similarity index 78% rename from splinter/src/Core/Diagonal.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/Diagonal.h index 68cf6d4b04..afcaf35756 100644 --- a/splinter/src/Core/Diagonal.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Diagonal.h @@ -21,7 +21,7 @@ namespace Eigen { * \param MatrixType the type of the object in which we are taking a sub/main/super diagonal * \param DiagIndex the index of the sub/super diagonal. The default is 0 and it means the main diagonal. * A positive value means a superdiagonal, a negative value means a subdiagonal. - * You can also use Dynamic so the index can be set at runtime. + * You can also use DynamicIndex so the index can be set at runtime. * * The matrix is not required to be square. * @@ -37,7 +37,7 @@ template struct traits > : traits { - typedef typename nested::type MatrixTypeNested; + typedef typename ref_selector::type MatrixTypeNested; typedef typename remove_reference::type _MatrixTypeNested; typedef typename MatrixType::StorageKind StorageKind; enum { @@ -52,8 +52,7 @@ struct traits > 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, - CoeffReadCost = _MatrixTypeNested::CoeffReadCost, + Flags = (unsigned int)_MatrixTypeNested::Flags & (RowMajorBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit, // FIXME DirectAccessBit should not be handled by expressions MatrixTypeOuterStride = outer_stride_at_compile_time::ret, InnerStrideAtCompileTime = MatrixTypeOuterStride == Dynamic ? Dynamic : MatrixTypeOuterStride+1, OuterStrideAtCompileTime = 0 @@ -70,20 +69,31 @@ template class Diagonal typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Diagonal) - inline Diagonal(MatrixType& matrix, Index a_index = DiagIndex) : m_matrix(matrix), m_index(a_index) {} + EIGEN_DEVICE_FUNC + explicit inline Diagonal(MatrixType& matrix, Index a_index = DiagIndex) : m_matrix(matrix), m_index(a_index) + { + eigen_assert( a_index <= m_matrix.cols() && -a_index <= m_matrix.rows() ); + } EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Diagonal) + EIGEN_DEVICE_FUNC inline Index rows() const - { return m_index.value()<0 ? (std::min)(m_matrix.cols(),m_matrix.rows()+m_index.value()) : (std::min)(m_matrix.rows(),m_matrix.cols()-m_index.value()); } + { + return m_index.value()<0 ? numext::mini(m_matrix.cols(),m_matrix.rows()+m_index.value()) + : numext::mini(m_matrix.rows(),m_matrix.cols()-m_index.value()); + } + EIGEN_DEVICE_FUNC inline Index cols() const { return 1; } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_matrix.outerStride() + 1; } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return 0; @@ -95,62 +105,75 @@ template class Diagonal 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())); } + EIGEN_DEVICE_FUNC + inline ScalarWithConstIfNotLvalue* data() { return &(m_matrix.coeffRef(rowOffset(), colOffset())); } + EIGEN_DEVICE_FUNC + inline const Scalar* data() const { return &(m_matrix.coeffRef(rowOffset(), colOffset())); } + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index) { EIGEN_STATIC_ASSERT_LVALUE(MatrixType) - return m_matrix.const_cast_derived().coeffRef(row+rowOffset(), row+colOffset()); + return m_matrix.coeffRef(row+rowOffset(), row+colOffset()); } + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index row, Index) const { - return m_matrix.const_cast_derived().coeffRef(row+rowOffset(), row+colOffset()); + return m_matrix.coeffRef(row+rowOffset(), row+colOffset()); } + EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index row, Index) const { return m_matrix.coeff(row+rowOffset(), row+colOffset()); } + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index idx) { EIGEN_STATIC_ASSERT_LVALUE(MatrixType) - return m_matrix.const_cast_derived().coeffRef(idx+rowOffset(), idx+colOffset()); + return m_matrix.coeffRef(idx+rowOffset(), idx+colOffset()); } + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index idx) const { - return m_matrix.const_cast_derived().coeffRef(idx+rowOffset(), idx+colOffset()); + return m_matrix.coeffRef(idx+rowOffset(), idx+colOffset()); } + EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index idx) const { return m_matrix.coeff(idx+rowOffset(), idx+colOffset()); } - const typename internal::remove_all::type& + EIGEN_DEVICE_FUNC + inline const typename internal::remove_all::type& nestedExpression() const { return m_matrix; } - int index() const + EIGEN_DEVICE_FUNC + inline Index index() const { return m_index.value(); } protected: - typename MatrixType::Nested m_matrix; + typename internal::ref_selector::non_const_type m_matrix; const internal::variable_if_dynamicindex m_index; private: // some compilers may fail to optimize std::max etc in case of compile-time constants... + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index absDiagIndex() const { return m_index.value()>0 ? m_index.value() : -m_index.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rowOffset() const { return m_index.value()>0 ? 0 : -m_index.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index colOffset() const { return m_index.value()>0 ? m_index.value() : 0; } - // triger a compile time error is someone try to call packet + // trigger a compile-time error if someone try to call packet template typename MatrixType::PacketReturnType packet(Index) const; template typename MatrixType::PacketReturnType packet(Index,Index) const; }; @@ -167,7 +190,7 @@ template inline typename MatrixBase::DiagonalReturnType MatrixBase::diagonal() { - return derived(); + return DiagonalReturnType(derived()); } /** This is the const version of diagonal(). */ @@ -216,20 +239,20 @@ MatrixBase::diagonal(Index index) const * * \sa MatrixBase::diagonal(), class Diagonal */ template -template -inline typename MatrixBase::template DiagonalIndexReturnType::Type +template +inline typename MatrixBase::template DiagonalIndexReturnType::Type MatrixBase::diagonal() { - return derived(); + return typename DiagonalIndexReturnType::Type(derived()); } /** This is the const version of diagonal(). */ template -template -inline typename MatrixBase::template ConstDiagonalIndexReturnType::Type +template +inline typename MatrixBase::template ConstDiagonalIndexReturnType::Type MatrixBase::diagonal() const { - return derived(); + return typename ConstDiagonalIndexReturnType::Type(derived()); } } // end namespace Eigen diff --git a/splinter/src/Core/DiagonalMatrix.h b/splinter/thirdparty/Eigen/Eigen/src/Core/DiagonalMatrix.h similarity index 71% rename from splinter/src/Core/DiagonalMatrix.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/DiagonalMatrix.h index e6c220f419..ecfdce8efa 100644 --- a/splinter/src/Core/DiagonalMatrix.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/DiagonalMatrix.h @@ -22,7 +22,7 @@ class DiagonalBase : public EigenBase typedef typename DiagonalVectorType::Scalar Scalar; typedef typename DiagonalVectorType::RealScalar RealScalar; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; + typedef typename internal::traits::StorageIndex StorageIndex; enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, @@ -30,79 +30,61 @@ class DiagonalBase : public EigenBase MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, IsVectorAtCompileTime = 0, - Flags = 0 + Flags = NoPreferredStorageOrderBit }; typedef Matrix DenseMatrixType; typedef DenseMatrixType DenseType; typedef DiagonalMatrix PlainObject; + EIGEN_DEVICE_FUNC inline const Derived& derived() const { return *static_cast(this); } + EIGEN_DEVICE_FUNC inline Derived& derived() { return *static_cast(this); } + EIGEN_DEVICE_FUNC DenseMatrixType toDenseMatrix() const { return derived(); } - template - void evalTo(MatrixBase &other) const; - template - void addTo(MatrixBase &other) const - { other.diagonal() += diagonal(); } - template - void subTo(MatrixBase &other) const - { other.diagonal() -= diagonal(); } - + + EIGEN_DEVICE_FUNC inline const DiagonalVectorType& diagonal() const { return derived().diagonal(); } + EIGEN_DEVICE_FUNC inline DiagonalVectorType& diagonal() { return derived().diagonal(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return diagonal().size(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return diagonal().size(); } - /** \returns the diagonal matrix product of \c *this by the matrix \a matrix. - */ template - const DiagonalProduct + EIGEN_DEVICE_FUNC + const Product operator*(const MatrixBase &matrix) const { - return DiagonalProduct(matrix.derived(), derived()); + return Product(derived(),matrix.derived()); } - inline const DiagonalWrapper, const DiagonalVectorType> > + typedef DiagonalWrapper, const DiagonalVectorType> > InverseReturnType; + EIGEN_DEVICE_FUNC + inline const InverseReturnType inverse() const { - return diagonal().cwiseInverse(); + return InverseReturnType(diagonal().cwiseInverse()); } - inline const DiagonalWrapper, const DiagonalVectorType> > + EIGEN_DEVICE_FUNC + inline const DiagonalWrapper operator*(const Scalar& scalar) const { - return diagonal() * scalar; + return DiagonalWrapper(diagonal() * scalar); } - friend inline const DiagonalWrapper, const DiagonalVectorType> > + EIGEN_DEVICE_FUNC + friend inline const DiagonalWrapper operator*(const Scalar& scalar, const DiagonalBase& other) { - return other.diagonal() * scalar; - } - - #ifdef EIGEN2_SUPPORT - template - bool isApprox(const DiagonalBase& other, typename NumTraits::Real precision = NumTraits::dummy_precision()) const - { - return diagonal().isApprox(other.diagonal(), precision); + return DiagonalWrapper(scalar * other.diagonal()); } - template - bool isApprox(const MatrixBase& other, typename NumTraits::Real precision = NumTraits::dummy_precision()) const - { - return toDenseMatrix().isApprox(other, precision); - } - #endif }; -template -template -void DiagonalBase::evalTo(MatrixBase &other) const -{ - other.setZero(); - other.diagonal() = diagonal(); -} #endif /** \class DiagonalMatrix @@ -124,10 +106,9 @@ struct traits > : traits > { typedef Matrix<_Scalar,SizeAtCompileTime,1,0,MaxSizeAtCompileTime,1> DiagonalVectorType; - typedef Dense StorageKind; - typedef DenseIndex Index; + typedef DiagonalShape StorageKind; enum { - Flags = LvalueBit + Flags = LvalueBit | NoPreferredStorageOrderBit }; }; } @@ -141,7 +122,7 @@ class DiagonalMatrix typedef const DiagonalMatrix& Nested; typedef _Scalar Scalar; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; + typedef typename internal::traits::StorageIndex StorageIndex; #endif protected: @@ -151,24 +132,31 @@ class DiagonalMatrix public: /** const version of diagonal(). */ + EIGEN_DEVICE_FUNC inline const DiagonalVectorType& diagonal() const { return m_diagonal; } /** \returns a reference to the stored vector of diagonal coefficients. */ + EIGEN_DEVICE_FUNC inline DiagonalVectorType& diagonal() { return m_diagonal; } /** Default constructor without initialization */ + EIGEN_DEVICE_FUNC inline DiagonalMatrix() {} /** Constructs a diagonal matrix with given dimension */ - inline DiagonalMatrix(Index dim) : m_diagonal(dim) {} + EIGEN_DEVICE_FUNC + explicit inline DiagonalMatrix(Index dim) : m_diagonal(dim) {} /** 2D constructor. */ + EIGEN_DEVICE_FUNC inline DiagonalMatrix(const Scalar& x, const Scalar& y) : m_diagonal(x,y) {} /** 3D constructor. */ + EIGEN_DEVICE_FUNC inline DiagonalMatrix(const Scalar& x, const Scalar& y, const Scalar& z) : m_diagonal(x,y,z) {} /** Copy constructor. */ template + EIGEN_DEVICE_FUNC inline DiagonalMatrix(const DiagonalBase& other) : m_diagonal(other.diagonal()) {} #ifndef EIGEN_PARSED_BY_DOXYGEN @@ -178,11 +166,13 @@ class DiagonalMatrix /** generic constructor from expression of the diagonal coefficients */ template + EIGEN_DEVICE_FUNC explicit inline DiagonalMatrix(const MatrixBase& other) : m_diagonal(other) {} /** Copy operator. */ template + EIGEN_DEVICE_FUNC DiagonalMatrix& operator=(const DiagonalBase& other) { m_diagonal = other.diagonal(); @@ -193,6 +183,7 @@ class DiagonalMatrix /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ + EIGEN_DEVICE_FUNC DiagonalMatrix& operator=(const DiagonalMatrix& other) { m_diagonal = other.diagonal(); @@ -201,14 +192,19 @@ class DiagonalMatrix #endif /** Resizes to given size. */ + EIGEN_DEVICE_FUNC inline void resize(Index size) { m_diagonal.resize(size); } /** Sets all coefficients to zero. */ + EIGEN_DEVICE_FUNC inline void setZero() { m_diagonal.setZero(); } /** Resizes and sets all coefficients to zero. */ + EIGEN_DEVICE_FUNC inline void setZero(Index size) { m_diagonal.setZero(size); } /** Sets this matrix to be the identity matrix of the current size. */ + EIGEN_DEVICE_FUNC inline void setIdentity() { m_diagonal.setOnes(); } /** Sets this matrix to be the identity matrix of the given size. */ + EIGEN_DEVICE_FUNC inline void setIdentity(Index size) { m_diagonal.setOnes(size); } }; @@ -232,14 +228,15 @@ struct traits > { typedef _DiagonalVectorType DiagonalVectorType; typedef typename DiagonalVectorType::Scalar Scalar; - typedef typename DiagonalVectorType::Index Index; - typedef typename DiagonalVectorType::StorageKind StorageKind; + typedef typename DiagonalVectorType::StorageIndex StorageIndex; + typedef DiagonalShape StorageKind; + typedef typename traits::XprKind XprKind; enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - MaxRowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - MaxColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - Flags = traits::Flags & LvalueBit + MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, + MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, + Flags = (traits::Flags & LvalueBit) | NoPreferredStorageOrderBit }; }; } @@ -255,9 +252,11 @@ class DiagonalWrapper #endif /** Constructor from expression of diagonal coefficients to wrap. */ - inline DiagonalWrapper(DiagonalVectorType& a_diagonal) : m_diagonal(a_diagonal) {} + EIGEN_DEVICE_FUNC + explicit inline DiagonalWrapper(DiagonalVectorType& a_diagonal) : m_diagonal(a_diagonal) {} /** \returns a const reference to the wrapped expression of diagonal coefficients. */ + EIGEN_DEVICE_FUNC const DiagonalVectorType& diagonal() const { return m_diagonal; } protected: @@ -277,7 +276,7 @@ template inline const DiagonalWrapper MatrixBase::asDiagonal() const { - return derived(); + return DiagonalWrapper(derived()); } /** \returns true if *this is approximately equal to a diagonal matrix, @@ -291,12 +290,11 @@ MatrixBase::asDiagonal() const template bool MatrixBase::isDiagonal(const RealScalar& prec) const { - using std::abs; if(cols() != rows()) return false; RealScalar maxAbsOnDiagonal = static_cast(-1); for(Index j = 0; j < cols(); ++j) { - RealScalar absOnDiagonal = abs(coeff(j,j)); + RealScalar absOnDiagonal = numext::abs(coeff(j,j)); if(absOnDiagonal > maxAbsOnDiagonal) maxAbsOnDiagonal = absOnDiagonal; } for(Index j = 0; j < cols(); ++j) @@ -308,6 +306,38 @@ bool MatrixBase::isDiagonal(const RealScalar& prec) const return true; } +namespace internal { + +template<> struct storage_kind_to_shape { typedef DiagonalShape Shape; }; + +struct Diagonal2Dense {}; + +template<> struct AssignmentKind { typedef Diagonal2Dense Kind; }; + +// Diagonal matrix to Dense assignment +template< typename DstXprType, typename SrcXprType, typename Functor> +struct Assignment +{ + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + dst.setZero(); + dst.diagonal() = src.diagonal(); + } + + static void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &/*func*/) + { dst.diagonal() += src.diagonal(); } + + static void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &/*func*/) + { dst.diagonal() -= src.diagonal(); } +}; + +} // namespace internal + } // end namespace Eigen #endif // EIGEN_DIAGONALMATRIX_H diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/DiagonalProduct.h b/splinter/thirdparty/Eigen/Eigen/src/Core/DiagonalProduct.h new file mode 100644 index 0000000000..d372b938f6 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/DiagonalProduct.h @@ -0,0 +1,28 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2007-2009 Benoit Jacob +// +// 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 { + +/** \returns the diagonal matrix product of \c *this by the diagonal matrix \a diagonal. + */ +template +template +inline const Product +MatrixBase::operator*(const DiagonalBase &a_diagonal) const +{ + return Product(derived(),a_diagonal.derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_DIAGONALPRODUCT_H diff --git a/splinter/src/Core/Dot.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Dot.h similarity index 54% rename from splinter/src/Core/Dot.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/Dot.h index 9d7651f1fd..1fe7a84a48 100644 --- a/splinter/src/Core/Dot.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Dot.h @@ -28,26 +28,33 @@ template struct dot_nocheck { - typedef typename scalar_product_traits::Scalar,typename traits::Scalar>::ReturnType ResScalar; - static inline ResScalar run(const MatrixBase& a, const MatrixBase& b) + typedef scalar_conj_product_op::Scalar,typename traits::Scalar> conj_prod; + typedef typename conj_prod::result_type ResScalar; + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE + static ResScalar run(const MatrixBase& a, const MatrixBase& b) { - return a.template binaryExpr::Scalar,typename traits::Scalar> >(b).sum(); + return a.template binaryExpr(b).sum(); } }; template struct dot_nocheck { - typedef typename scalar_product_traits::Scalar,typename traits::Scalar>::ReturnType ResScalar; - static inline ResScalar run(const MatrixBase& a, const MatrixBase& b) + typedef scalar_conj_product_op::Scalar,typename traits::Scalar> conj_prod; + typedef typename conj_prod::result_type ResScalar; + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE + static ResScalar run(const MatrixBase& a, const MatrixBase& b) { - return a.transpose().template binaryExpr::Scalar,typename traits::Scalar> >(b).sum(); + return a.transpose().template binaryExpr(b).sum(); } }; } // end namespace internal -/** \returns the dot product of *this with other. +/** \fn MatrixBase::dot + * \returns the dot product of *this with other. * * \only_for_vectors * @@ -59,55 +66,31 @@ struct dot_nocheck */ template template -typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE +typename ScalarBinaryOpTraits::Scalar,typename internal::traits::Scalar>::ReturnType MatrixBase::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) +#if !(defined(EIGEN_NO_STATIC_ASSERT) && defined(EIGEN_NO_DEBUG)) typedef internal::scalar_conj_product_op func; EIGEN_CHECK_BINARY_COMPATIBILIY(func,Scalar,typename OtherDerived::Scalar); - +#endif + eigen_assert(size() == other.size()); return internal::dot_nocheck::run(*this, other); } -#ifdef EIGEN2_SUPPORT -/** \returns the dot product of *this with other, with the Eigen2 convention that the dot product is linear in the first variable - * (conjugating the second variable). Of course this only makes a difference in the complex case. - * - * This method is only available in EIGEN2_SUPPORT mode. - * - * \only_for_vectors - * - * \sa dot() - */ -template -template -typename internal::traits::Scalar -MatrixBase::eigen2_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()); - - return internal::dot_nocheck::run(other,*this); -} -#endif - - //---------- implementation of L2 norm and related functions ---------- /** \returns, for vectors, the squared \em l2 norm of \c *this, and for matrices the Frobenius norm. * In both cases, it consists in the sum of the square of all the matrix entries. * For vectors, this is also equals to the dot product of \c *this with itself. * - * \sa dot(), norm() + * \sa dot(), norm(), lpNorm() */ template EIGEN_STRONG_INLINE typename NumTraits::Scalar>::Real MatrixBase::squaredNorm() const @@ -119,41 +102,98 @@ EIGEN_STRONG_INLINE typename NumTraits::Scala * In both cases, it consists in the square root of the sum of the square of all the matrix entries. * For vectors, this is also equals to the square root of the dot product of \c *this with itself. * - * \sa dot(), squaredNorm() + * \sa lpNorm(), dot(), squaredNorm() */ template -inline typename NumTraits::Scalar>::Real MatrixBase::norm() const +EIGEN_STRONG_INLINE typename NumTraits::Scalar>::Real MatrixBase::norm() const { - using std::sqrt; - return sqrt(squaredNorm()); + return numext::sqrt(squaredNorm()); } -/** \returns an expression of the quotient of *this by its own norm. +/** \returns an expression of the quotient of \c *this by its own norm. + * + * \warning If the input vector is too small (i.e., this->norm()==0), + * then this function returns a copy of the input. * * \only_for_vectors * * \sa norm(), normalize() */ template -inline const typename MatrixBase::PlainObject +EIGEN_STRONG_INLINE const typename MatrixBase::PlainObject MatrixBase::normalized() const { - typedef typename internal::nested::type Nested; - typedef typename internal::remove_reference::type _Nested; + typedef typename internal::nested_eval::type _Nested; _Nested n(derived()); - return n / n.norm(); + RealScalar z = n.squaredNorm(); + // NOTE: after extensive benchmarking, this conditional does not impact performance, at least on recent x86 CPU + if(z>RealScalar(0)) + return n / numext::sqrt(z); + else + return n; } /** Normalizes the vector, i.e. divides it by its own norm. * * \only_for_vectors * + * \warning If the input vector is too small (i.e., this->norm()==0), then \c *this is left unchanged. + * * \sa norm(), normalized() */ template -inline void MatrixBase::normalize() +EIGEN_STRONG_INLINE void MatrixBase::normalize() { - *this /= norm(); + RealScalar z = squaredNorm(); + // NOTE: after extensive benchmarking, this conditional does not impact performance, at least on recent x86 CPU + if(z>RealScalar(0)) + derived() /= numext::sqrt(z); +} + +/** \returns an expression of the quotient of \c *this by its own norm while avoiding underflow and overflow. + * + * \only_for_vectors + * + * This method is analogue to the normalized() method, but it reduces the risk of + * underflow and overflow when computing the norm. + * + * \warning If the input vector is too small (i.e., this->norm()==0), + * then this function returns a copy of the input. + * + * \sa stableNorm(), stableNormalize(), normalized() + */ +template +EIGEN_STRONG_INLINE const typename MatrixBase::PlainObject +MatrixBase::stableNormalized() const +{ + typedef typename internal::nested_eval::type _Nested; + _Nested n(derived()); + RealScalar w = n.cwiseAbs().maxCoeff(); + RealScalar z = (n/w).squaredNorm(); + if(z>RealScalar(0)) + return n / (numext::sqrt(z)*w); + else + return n; +} + +/** Normalizes the vector while avoid underflow and overflow + * + * \only_for_vectors + * + * This method is analogue to the normalize() method, but it reduces the risk of + * underflow and overflow when computing the norm. + * + * \warning If the input vector is too small (i.e., this->norm()==0), then \c *this is left unchanged. + * + * \sa stableNorm(), stableNormalized(), normalize() + */ +template +EIGEN_STRONG_INLINE void MatrixBase::stableNormalize() +{ + RealScalar w = cwiseAbs().maxCoeff(); + RealScalar z = (derived()/w).squaredNorm(); + if(z>RealScalar(0)) + derived() /= numext::sqrt(z)*w; } //---------- implementation of other norms ---------- @@ -164,9 +204,10 @@ template struct lpNorm_selector { typedef typename NumTraits::Scalar>::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar run(const MatrixBase& m) { - using std::pow; + EIGEN_USING_STD_MATH(pow) return pow(m.cwiseAbs().array().pow(p).sum(), RealScalar(1)/p); } }; @@ -174,6 +215,7 @@ struct lpNorm_selector template struct lpNorm_selector { + EIGEN_DEVICE_FUNC static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) { return m.cwiseAbs().sum(); @@ -183,6 +225,7 @@ struct lpNorm_selector template struct lpNorm_selector { + EIGEN_DEVICE_FUNC static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) { return m.norm(); @@ -192,23 +235,35 @@ struct lpNorm_selector template struct lpNorm_selector { - static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) + typedef typename NumTraits::Scalar>::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const MatrixBase& m) { + if(Derived::SizeAtCompileTime==0 || (Derived::SizeAtCompileTime==Dynamic && m.size()==0)) + return RealScalar(0); return m.cwiseAbs().maxCoeff(); } }; } // end namespace internal -/** \returns the \f$ \ell^p \f$ norm of *this, that is, returns the p-th root of the sum of the p-th powers of the absolute values - * of the coefficients of *this. If \a p is the special value \a Eigen::Infinity, this function returns the \f$ \ell^\infty \f$ - * norm, that is the maximum of the absolute values of the coefficients of *this. +/** \returns the \b coefficient-wise \f$ \ell^p \f$ norm of \c *this, that is, returns the p-th root of the sum of the p-th powers of the absolute values + * of the coefficients of \c *this. If \a p is the special value \a Eigen::Infinity, this function returns the \f$ \ell^\infty \f$ + * norm, that is the maximum of the absolute values of the coefficients of \c *this. + * + * In all cases, if \c *this is empty, then the value 0 is returned. + * + * \note For matrices, this function does not compute the operator-norm. That is, if \c *this is a matrix, then its coefficients are interpreted as a 1D vector. Nonetheless, you can easily compute the 1-norm and \f$\infty\f$-norm matrix operator norms using \link TutorialReductionsVisitorsBroadcastingReductionsNorm partial reductions \endlink. * * \sa norm() */ template template +#ifndef EIGEN_PARSED_BY_DOXYGEN inline typename NumTraits::Scalar>::Real +#else +MatrixBase::RealScalar +#endif MatrixBase::lpNorm() const { return internal::lpNorm_selector::run(*this); @@ -227,8 +282,8 @@ template bool MatrixBase::isOrthogonal (const MatrixBase& other, const RealScalar& prec) const { - typename internal::nested::type nested(derived()); - typename internal::nested::type otherNested(other.derived()); + typename internal::nested_eval::type nested(derived()); + typename internal::nested_eval::type otherNested(other.derived()); return numext::abs2(nested.dot(otherNested)) <= prec * prec * nested.squaredNorm() * otherNested.squaredNorm(); } @@ -246,13 +301,13 @@ bool MatrixBase::isOrthogonal template bool MatrixBase::isUnitary(const RealScalar& prec) const { - typename Derived::Nested nested(derived()); + typename internal::nested_eval::type self(derived()); for(Index i = 0; i < cols(); ++i) { - if(!internal::isApprox(nested.col(i).squaredNorm(), static_cast(1), prec)) + if(!internal::isApprox(self.col(i).squaredNorm(), static_cast(1), prec)) return false; for(Index j = 0; j < i; ++j) - if(!internal::isMuchSmallerThan(nested.col(i).dot(nested.col(j)), static_cast(1), prec)) + if(!internal::isMuchSmallerThan(self.col(i).dot(self.col(j)), static_cast(1), prec)) return false; } return true; diff --git a/splinter/src/Core/EigenBase.h b/splinter/thirdparty/Eigen/Eigen/src/Core/EigenBase.h similarity index 74% rename from splinter/src/Core/EigenBase.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/EigenBase.h index fadb45852f..b195506a91 100644 --- a/splinter/src/Core/EigenBase.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/EigenBase.h @@ -13,7 +13,10 @@ namespace Eigen { -/** Common base class for all classes T such that MatrixBase has an operator=(T) and a constructor MatrixBase(T). +/** \class EigenBase + * \ingroup Core_Module + * + * Common base class for all classes T such that MatrixBase has an operator=(T) and a constructor MatrixBase(T). * * In other words, an EigenBase object is an object that can be copied into a MatrixBase. * @@ -21,39 +24,57 @@ namespace Eigen { * * Notice that this class is trivial, it is only used to disambiguate overloaded functions. * - * \sa \ref TopicClassHierarchy + * \sa \blank \ref TopicClassHierarchy */ template struct EigenBase { // typedef typename internal::plain_matrix_type::type PlainObject; - + + /** \brief The interface type of indices + * \details To change this, \c \#define the preprocessor symbol \c EIGEN_DEFAULT_DENSE_INDEX_TYPE. + * \deprecated Since Eigen 3.3, its usage is deprecated. Use Eigen::Index instead. + * \sa StorageIndex, \ref TopicPreprocessorDirectives. + */ + typedef Eigen::Index Index; + + // FIXME is it needed? typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; /** \returns a reference to the derived object */ + EIGEN_DEVICE_FUNC Derived& derived() { return *static_cast(this); } /** \returns a const reference to the derived object */ + EIGEN_DEVICE_FUNC const Derived& derived() const { return *static_cast(this); } + EIGEN_DEVICE_FUNC inline Derived& const_cast_derived() const { return *static_cast(const_cast(this)); } + EIGEN_DEVICE_FUNC inline const Derived& const_derived() const { return *static_cast(this); } /** \returns the number of rows. \sa cols(), RowsAtCompileTime */ + EIGEN_DEVICE_FUNC inline Index rows() const { return derived().rows(); } /** \returns the number of columns. \sa rows(), ColsAtCompileTime*/ + EIGEN_DEVICE_FUNC inline Index cols() const { return derived().cols(); } /** \returns the number of coefficients, which is rows()*cols(). * \sa rows(), cols(), SizeAtCompileTime. */ + EIGEN_DEVICE_FUNC inline Index size() const { return rows() * cols(); } /** \internal Don't use it, but do the equivalent: \code dst = *this; \endcode */ - template inline void evalTo(Dest& dst) const + template + EIGEN_DEVICE_FUNC + inline void evalTo(Dest& dst) const { derived().evalTo(dst); } /** \internal Don't use it, but do the equivalent: \code dst += *this; \endcode */ - template inline void addTo(Dest& dst) const + template + EIGEN_DEVICE_FUNC + inline void addTo(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. @@ -63,7 +84,9 @@ template struct EigenBase } /** \internal Don't use it, but do the equivalent: \code dst -= *this; \endcode */ - template inline void subTo(Dest& dst) const + template + EIGEN_DEVICE_FUNC + inline void subTo(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. @@ -73,7 +96,8 @@ template struct EigenBase } /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheRight(*this); \endcode */ - template inline void applyThisOnTheRight(Dest& dst) const + template + EIGEN_DEVICE_FUNC inline void applyThisOnTheRight(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. @@ -81,7 +105,8 @@ template struct EigenBase } /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheLeft(*this); \endcode */ - template inline void applyThisOnTheLeft(Dest& dst) const + template + EIGEN_DEVICE_FUNC inline void applyThisOnTheLeft(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. @@ -104,25 +129,28 @@ template struct EigenBase */ template template +EIGEN_DEVICE_FUNC Derived& DenseBase::operator=(const EigenBase &other) { - other.derived().evalTo(derived()); + call_assignment(derived(), other.derived()); return derived(); } template template +EIGEN_DEVICE_FUNC Derived& DenseBase::operator+=(const EigenBase &other) { - other.derived().addTo(derived()); + call_assignment(derived(), other.derived(), internal::add_assign_op()); return derived(); } template template +EIGEN_DEVICE_FUNC Derived& DenseBase::operator-=(const EigenBase &other) { - other.derived().subTo(derived()); + call_assignment(derived(), other.derived(), internal::sub_assign_op()); return derived(); } diff --git a/splinter/src/Core/ForceAlignedAccess.h b/splinter/thirdparty/Eigen/Eigen/src/Core/ForceAlignedAccess.h similarity index 79% rename from splinter/src/Core/ForceAlignedAccess.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/ForceAlignedAccess.h index 807c7a2934..7b08b45e67 100644 --- a/splinter/src/Core/ForceAlignedAccess.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/ForceAlignedAccess.h @@ -39,29 +39,29 @@ template class ForceAlignedAccess typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(ForceAlignedAccess) - inline ForceAlignedAccess(const ExpressionType& matrix) : m_expression(matrix) {} + EIGEN_DEVICE_FUNC explicit inline ForceAlignedAccess(const ExpressionType& matrix) : m_expression(matrix) {} - inline Index rows() const { return m_expression.rows(); } - inline Index cols() const { return m_expression.cols(); } - inline Index outerStride() const { return m_expression.outerStride(); } - inline Index innerStride() const { return m_expression.innerStride(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } - inline const CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index row, Index col) const { return m_expression.coeff(row, col); } - inline Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { return m_expression.const_cast_derived().coeffRef(row, col); } - inline const CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } - inline Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) { return m_expression.const_cast_derived().coeffRef(index); } @@ -90,7 +90,7 @@ template class ForceAlignedAccess m_expression.const_cast_derived().template writePacket(index, x); } - operator const ExpressionType&() const { return m_expression; } + EIGEN_DEVICE_FUNC operator const ExpressionType&() const { return m_expression; } protected: const ExpressionType& m_expression; @@ -127,7 +127,7 @@ template inline typename internal::add_const_on_value_type,Derived&>::type>::type MatrixBase::forceAlignedAccessIf() const { - return derived(); + return derived(); // FIXME This should not work but apparently is never used } /** \returns an expression of *this with forced aligned access if \a Enable is true. @@ -138,7 +138,7 @@ template inline typename internal::conditional,Derived&>::type MatrixBase::forceAlignedAccessIf() { - return derived(); + return derived(); // FIXME This should not work but apparently is never used } } // end namespace Eigen diff --git a/splinter/src/Core/Fuzzy.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Fuzzy.h similarity index 94% rename from splinter/src/Core/Fuzzy.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/Fuzzy.h index fe63bd2984..3e403a09d9 100644 --- a/splinter/src/Core/Fuzzy.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Fuzzy.h @@ -19,18 +19,19 @@ namespace internal template::IsInteger> struct isApprox_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) { - using std::min; - 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()); + typename internal::nested_eval::type nested(x); + typename internal::nested_eval::type otherNested(y); + return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * numext::mini(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); } }; template struct isApprox_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar&) { return x.matrix() == y.matrix(); @@ -40,6 +41,7 @@ struct isApprox_selector template::IsInteger> struct isMuchSmallerThan_object_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) { return x.cwiseAbs2().sum() <= numext::abs2(prec) * y.cwiseAbs2().sum(); @@ -49,6 +51,7 @@ struct isMuchSmallerThan_object_selector template struct isMuchSmallerThan_object_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived&, const typename Derived::RealScalar&) { return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix(); @@ -58,6 +61,7 @@ struct isMuchSmallerThan_object_selector template::IsInteger> struct isMuchSmallerThan_scalar_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const typename Derived::RealScalar& y, const typename Derived::RealScalar& prec) { return x.cwiseAbs2().sum() <= numext::abs2(prec * y); @@ -67,6 +71,7 @@ struct isMuchSmallerThan_scalar_selector template struct isMuchSmallerThan_scalar_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const typename Derived::RealScalar&, const typename Derived::RealScalar&) { return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix(); diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/GeneralProduct.h b/splinter/thirdparty/Eigen/Eigen/src/Core/GeneralProduct.h new file mode 100644 index 0000000000..6f0cc80e94 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/GeneralProduct.h @@ -0,0 +1,455 @@ +// 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 { + +enum { + Large = 2, + Small = 3 +}; + +namespace internal { + +template struct product_type_selector; + +template struct product_size_category +{ + enum { + #ifndef EIGEN_CUDA_ARCH + is_large = MaxSize == Dynamic || + Size >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD || + (Size==Dynamic && MaxSize>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD), + #else + is_large = 0, + #endif + 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 = traits<_Lhs>::MaxRowsAtCompileTime, + Rows = traits<_Lhs>::RowsAtCompileTime, + MaxCols = traits<_Rhs>::MaxColsAtCompileTime, + Cols = traits<_Rhs>::ColsAtCompileTime, + MaxDepth = EIGEN_SIZE_MIN_PREFER_FIXED(traits<_Lhs>::MaxColsAtCompileTime, + traits<_Rhs>::MaxRowsAtCompileTime), + Depth = EIGEN_SIZE_MIN_PREFER_FIXED(traits<_Lhs>::ColsAtCompileTime, + traits<_Rhs>::RowsAtCompileTime) + }; + + // 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, + ret = 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 { enum { ret = LazyCoeffBasedProductMode }; }; +template struct product_type_selector<1, N, 1> { enum { ret = LazyCoeffBasedProductMode }; }; +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 = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; + +} // end namespace internal + +/*********************************************************************** +* 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); + +/*********************************************************************** +* Implementation of Outer Vector Vector Product +***********************************************************************/ + +/*********************************************************************** +* Implementation of General Matrix Vector Product +***********************************************************************/ + +/* According to the shape/flags of the matrix we have to distinghish 3 different cases: + * 1 - the matrix is col-major, BLAS compatible and M is large => 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 gemv_dense_selector; + +} // end namespace internal + +namespace internal { + +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 +{ + enum { + ForceAlignment = internal::packet_traits::Vectorizable, + PacketSize = internal::packet_traits::size + }; + #if EIGEN_MAX_STATIC_ALIGN_BYTES!=0 + 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. + internal::plain_array m_data; + EIGEN_STRONG_INLINE Scalar* data() { + return ForceAlignment + ? reinterpret_cast((internal::UIntPtr(m_data.array) & ~(std::size_t(EIGEN_MAX_ALIGN_BYTES-1))) + EIGEN_MAX_ALIGN_BYTES) + : m_data.array; + } + #endif +}; + +// The vector is on the left => transposition +template +struct gemv_dense_selector +{ + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + Transpose destT(dest); + enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; + gemv_dense_selector + ::run(rhs.transpose(), lhs.transpose(), destT, alpha); + } +}; + +template<> struct gemv_dense_selector +{ + template + static inline void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + typedef typename Dest::Scalar ResScalar; + typedef typename Dest::RealScalar RealScalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + + typedef Map, EIGEN_PLAIN_ENUM_MIN(AlignedMax,internal::packet_traits::size)> MappedDest; + + ActualLhsType actualLhs = LhsBlasTraits::extract(lhs); + ActualRhsType actualRhs = RhsBlasTraits::extract(rhs); + + ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(lhs) + * RhsBlasTraits::extractScalarFactor(rhs); + + // make sure Dest is a compile-time vector type (bug 1166) + typedef typename conditional::type ActualDest; + + 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 = (ActualDest::InnerStrideAtCompileTime==1), + ComplexByReal = (NumTraits::IsComplex) && (!NumTraits::IsComplex), + MightCannotUseDest = (!EvalToDestAtCompileTime) || ComplexByReal + }; + + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; + RhsScalar compatibleAlpha = get_factor::run(actualAlpha); + + if(!MightCannotUseDest) + { + // shortcut if we are sure to be able to use dest directly, + // this ease the compiler to generate cleaner and more optimzized code for most common cases + general_matrix_vector_product + ::run( + actualLhs.rows(), actualLhs.cols(), + LhsMapper(actualLhs.data(), actualLhs.outerStride()), + RhsMapper(actualRhs.data(), actualRhs.innerStride()), + dest.data(), 1, + compatibleAlpha); + } + else + { + gemv_static_vector_if static_dest; + + const bool alphaIsCompatible = (!ComplexByReal) || (numext::imag(actualAlpha)==RealScalar(0)); + const bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible; + + ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(), + evalToDest ? dest.data() : static_dest.data()); + + if(!evalToDest) + { + #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN + Index 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(), + LhsMapper(actualLhs.data(), actualLhs.outerStride()), + RhsMapper(actualRhs.data(), actualRhs.innerStride()), + actualDestPtr, 1, + compatibleAlpha); + + if (!evalToDest) + { + if(!alphaIsCompatible) + dest.matrix() += actualAlpha * MappedDest(actualDestPtr, dest.size()); + else + dest = MappedDest(actualDestPtr, dest.size()); + } + } + } +}; + +template<> struct gemv_dense_selector +{ + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + typedef typename Dest::Scalar ResScalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + typedef typename internal::remove_all::type ActualRhsTypeCleaned; + + typename add_const::type actualLhs = LhsBlasTraits::extract(lhs); + typename add_const::type actualRhs = RhsBlasTraits::extract(rhs); + + ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(lhs) + * RhsBlasTraits::extractScalarFactor(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 = ActualRhsTypeCleaned::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 + Index size = actualRhs.size(); + EIGEN_DENSE_STORAGE_CTOR_PLUGIN + #endif + Map(actualRhsPtr, actualRhs.size()) = actualRhs; + } + + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; + general_matrix_vector_product + ::run( + actualLhs.rows(), actualLhs.cols(), + LhsMapper(actualLhs.data(), actualLhs.outerStride()), + RhsMapper(actualRhsPtr, 1), + dest.data(), dest.col(0).innerStride(), //NOTE if dest is not a vector at compile-time, then dest.innerStride() might be wrong. (bug 1166) + actualAlpha); + } +}; + +template<> struct gemv_dense_selector +{ + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + EIGEN_STATIC_ASSERT((!nested_eval::Evaluate),EIGEN_INTERNAL_COMPILATION_ERROR_OR_YOU_MADE_A_PROGRAMMING_MISTAKE); + // TODO if rhs is large enough it might be beneficial to make sure that dest is sequentially stored in memory, otherwise use a temp + typename nested_eval::type actual_rhs(rhs); + const Index size = rhs.rows(); + for(Index k=0; k struct gemv_dense_selector +{ + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + EIGEN_STATIC_ASSERT((!nested_eval::Evaluate),EIGEN_INTERNAL_COMPILATION_ERROR_OR_YOU_MADE_A_PROGRAMMING_MISTAKE); + typename nested_eval::type actual_rhs(rhs); + const Index rows = dest.rows(); + for(Index i=0; i +template +inline const Product +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 Product(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 Product +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 Product(derived(), other.derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_PRODUCT_H diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/GenericPacketMath.h b/splinter/thirdparty/Eigen/Eigen/src/Core/GenericPacketMath.h new file mode 100644 index 0000000000..029f8ac36f --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/GenericPacketMath.h @@ -0,0 +1,593 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// 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 + * \file GenericPacketMath.h + * + * Default implementation for types not supported by the vectorization. + * In practice these functions are provided to make easier the writing + * of generic vectorized code. + */ + +#ifndef EIGEN_DEBUG_ALIGNED_LOAD +#define EIGEN_DEBUG_ALIGNED_LOAD +#endif + +#ifndef EIGEN_DEBUG_UNALIGNED_LOAD +#define EIGEN_DEBUG_UNALIGNED_LOAD +#endif + +#ifndef EIGEN_DEBUG_ALIGNED_STORE +#define EIGEN_DEBUG_ALIGNED_STORE +#endif + +#ifndef EIGEN_DEBUG_UNALIGNED_STORE +#define EIGEN_DEBUG_UNALIGNED_STORE +#endif + +struct default_packet_traits +{ + enum { + HasHalfPacket = 0, + + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasNegate = 1, + HasAbs = 1, + HasArg = 0, + HasAbs2 = 1, + HasMin = 1, + HasMax = 1, + HasConj = 1, + HasSetLinear = 1, + HasBlend = 0, + + HasDiv = 0, + HasSqrt = 0, + HasRsqrt = 0, + HasExp = 0, + HasLog = 0, + HasLog1p = 0, + HasLog10 = 0, + HasPow = 0, + + HasSin = 0, + HasCos = 0, + HasTan = 0, + HasASin = 0, + HasACos = 0, + HasATan = 0, + HasSinh = 0, + HasCosh = 0, + HasTanh = 0, + HasLGamma = 0, + HasDiGamma = 0, + HasZeta = 0, + HasPolygamma = 0, + HasErf = 0, + HasErfc = 0, + HasIGamma = 0, + HasIGammac = 0, + HasBetaInc = 0, + + HasRound = 0, + HasFloor = 0, + HasCeil = 0, + + HasSign = 0 + }; +}; + +template struct packet_traits : default_packet_traits +{ + typedef T type; + typedef T half; + enum { + Vectorizable = 0, + size = 1, + AlignedOnScalar = 0, + HasHalfPacket = 0 + }; + enum { + HasAdd = 0, + HasSub = 0, + HasMul = 0, + HasNegate = 0, + HasAbs = 0, + HasAbs2 = 0, + HasMin = 0, + HasMax = 0, + HasConj = 0, + HasSetLinear = 0 + }; +}; + +template struct packet_traits : packet_traits { }; + +template struct type_casting_traits { + enum { + VectorizedCast = 0, + SrcCoeffRatio = 1, + TgtCoeffRatio = 1 + }; +}; + + +/** \internal \returns static_cast(a) (coeff-wise) */ +template +EIGEN_DEVICE_FUNC inline TgtPacket +pcast(const SrcPacket& a) { + return static_cast(a); +} +template +EIGEN_DEVICE_FUNC inline TgtPacket +pcast(const SrcPacket& a, const SrcPacket& /*b*/) { + return static_cast(a); +} + +template +EIGEN_DEVICE_FUNC inline TgtPacket +pcast(const SrcPacket& a, const SrcPacket& /*b*/, const SrcPacket& /*c*/, const SrcPacket& /*d*/) { + return static_cast(a); +} + +/** \internal \returns a + b (coeff-wise) */ +template EIGEN_DEVICE_FUNC inline Packet +padd(const Packet& a, + const Packet& b) { return a+b; } + +/** \internal \returns a - b (coeff-wise) */ +template EIGEN_DEVICE_FUNC inline Packet +psub(const Packet& a, + const Packet& b) { return a-b; } + +/** \internal \returns -a (coeff-wise) */ +template EIGEN_DEVICE_FUNC inline Packet +pnegate(const Packet& a) { return -a; } + +/** \internal \returns conj(a) (coeff-wise) */ + +template EIGEN_DEVICE_FUNC inline Packet +pconj(const Packet& a) { return numext::conj(a); } + +/** \internal \returns a * b (coeff-wise) */ +template EIGEN_DEVICE_FUNC inline Packet +pmul(const Packet& a, + const Packet& b) { return a*b; } + +/** \internal \returns a / b (coeff-wise) */ +template EIGEN_DEVICE_FUNC inline Packet +pdiv(const Packet& a, + const Packet& b) { return a/b; } + +/** \internal \returns the min of \a a and \a b (coeff-wise) */ +template EIGEN_DEVICE_FUNC inline Packet +pmin(const Packet& a, + const Packet& b) { return numext::mini(a, b); } + +/** \internal \returns the max of \a a and \a b (coeff-wise) */ +template EIGEN_DEVICE_FUNC inline Packet +pmax(const Packet& a, + const Packet& b) { return numext::maxi(a, b); } + +/** \internal \returns the absolute value of \a a */ +template EIGEN_DEVICE_FUNC inline Packet +pabs(const Packet& a) { using std::abs; return abs(a); } + +/** \internal \returns the phase angle of \a a */ +template EIGEN_DEVICE_FUNC inline Packet +parg(const Packet& a) { using numext::arg; return arg(a); } + +/** \internal \returns the bitwise and of \a a and \a b */ +template EIGEN_DEVICE_FUNC inline Packet +pand(const Packet& a, const Packet& b) { return a & b; } + +/** \internal \returns the bitwise or of \a a and \a b */ +template EIGEN_DEVICE_FUNC inline Packet +por(const Packet& a, const Packet& b) { return a | b; } + +/** \internal \returns the bitwise xor of \a a and \a b */ +template EIGEN_DEVICE_FUNC inline Packet +pxor(const Packet& a, const Packet& b) { return a ^ b; } + +/** \internal \returns the bitwise andnot of \a a and \a b */ +template EIGEN_DEVICE_FUNC inline Packet +pandnot(const Packet& a, const Packet& b) { return a & (!b); } + +/** \internal \returns a packet version of \a *from, from must be 16 bytes aligned */ +template EIGEN_DEVICE_FUNC inline Packet +pload(const typename unpacket_traits::type* from) { return *from; } + +/** \internal \returns a packet version of \a *from, (un-aligned load) */ +template EIGEN_DEVICE_FUNC inline Packet +ploadu(const typename unpacket_traits::type* from) { return *from; } + +/** \internal \returns a packet with constant coefficients \a a, e.g.: (a,a,a,a) */ +template EIGEN_DEVICE_FUNC inline Packet +pset1(const typename unpacket_traits::type& a) { return a; } + +/** \internal \returns a packet with constant coefficients \a a[0], e.g.: (a[0],a[0],a[0],a[0]) */ +template EIGEN_DEVICE_FUNC inline Packet +pload1(const typename unpacket_traits::type *a) { return pset1(*a); } + +/** \internal \returns a packet with elements of \a *from duplicated. + * For instance, for a packet of 8 elements, 4 scalars will be read from \a *from and + * duplicated to form: {from[0],from[0],from[1],from[1],from[2],from[2],from[3],from[3]} + * Currently, this function is only used for scalar * complex products. + */ +template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet +ploaddup(const typename unpacket_traits::type* from) { return *from; } + +/** \internal \returns a packet with elements of \a *from quadrupled. + * For instance, for a packet of 8 elements, 2 scalars will be read from \a *from and + * replicated to form: {from[0],from[0],from[0],from[0],from[1],from[1],from[1],from[1]} + * Currently, this function is only used in matrix products. + * For packet-size smaller or equal to 4, this function is equivalent to pload1 + */ +template EIGEN_DEVICE_FUNC inline Packet +ploadquad(const typename unpacket_traits::type* from) +{ return pload1(from); } + +/** \internal equivalent to + * \code + * a0 = pload1(a+0); + * a1 = pload1(a+1); + * a2 = pload1(a+2); + * a3 = pload1(a+3); + * \endcode + * \sa pset1, pload1, ploaddup, pbroadcast2 + */ +template EIGEN_DEVICE_FUNC +inline void pbroadcast4(const typename unpacket_traits::type *a, + Packet& a0, Packet& a1, Packet& a2, Packet& a3) +{ + a0 = pload1(a+0); + a1 = pload1(a+1); + a2 = pload1(a+2); + a3 = pload1(a+3); +} + +/** \internal equivalent to + * \code + * a0 = pload1(a+0); + * a1 = pload1(a+1); + * \endcode + * \sa pset1, pload1, ploaddup, pbroadcast4 + */ +template EIGEN_DEVICE_FUNC +inline void pbroadcast2(const typename unpacket_traits::type *a, + Packet& a0, Packet& a1) +{ + a0 = pload1(a+0); + a1 = pload1(a+1); +} + +/** \internal \brief Returns a packet with coefficients (a,a+1,...,a+packet_size-1). */ +template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet +plset(const typename unpacket_traits::type& a) { return a; } + +/** \internal copy the packet \a from to \a *to, \a to must be 16 bytes aligned */ +template EIGEN_DEVICE_FUNC inline void pstore(Scalar* to, const Packet& from) +{ (*to) = from; } + +/** \internal copy the packet \a from to \a *to, (un-aligned store) */ +template EIGEN_DEVICE_FUNC inline void pstoreu(Scalar* to, const Packet& from) +{ (*to) = from; } + + template EIGEN_DEVICE_FUNC inline Packet pgather(const Scalar* from, Index /*stride*/) + { return ploadu(from); } + + template EIGEN_DEVICE_FUNC inline void pscatter(Scalar* to, const Packet& from, Index /*stride*/) + { pstore(to, from); } + +/** \internal tries to do cache prefetching of \a addr */ +template EIGEN_DEVICE_FUNC inline void prefetch(const Scalar* addr) +{ +#ifdef __CUDA_ARCH__ +#if defined(__LP64__) + // 64-bit pointer operand constraint for inlined asm + asm(" prefetch.L1 [ %1 ];" : "=l"(addr) : "l"(addr)); +#else + // 32-bit pointer operand constraint for inlined asm + asm(" prefetch.L1 [ %1 ];" : "=r"(addr) : "r"(addr)); +#endif +#elif (!EIGEN_COMP_MSVC) && (EIGEN_COMP_GNUC || EIGEN_COMP_CLANG || EIGEN_COMP_ICC) + __builtin_prefetch(addr); +#endif +} + +/** \internal \returns the first element of a packet */ +template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type pfirst(const Packet& a) +{ return a; } + +/** \internal \returns a packet where the element i contains the sum of the packet of \a vec[i] */ +template EIGEN_DEVICE_FUNC inline Packet +preduxp(const Packet* vecs) { return vecs[0]; } + +/** \internal \returns the sum of the elements of \a a*/ +template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux(const Packet& a) +{ return a; } + +/** \internal \returns the sum of the elements of \a a by block of 4 elements. + * For a packet {a0, a1, a2, a3, a4, a5, a6, a7}, it returns a half packet {a0+a4, a1+a5, a2+a6, a3+a7} + * For packet-size smaller or equal to 4, this boils down to a noop. + */ +template EIGEN_DEVICE_FUNC inline +typename conditional<(unpacket_traits::size%8)==0,typename unpacket_traits::half,Packet>::type +predux_downto4(const Packet& a) +{ return a; } + +/** \internal \returns the product of the elements of \a a*/ +template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_mul(const Packet& a) +{ return a; } + +/** \internal \returns the min of the elements of \a a*/ +template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_min(const Packet& a) +{ return a; } + +/** \internal \returns the max of the elements of \a a*/ +template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_max(const Packet& a) +{ return a; } + +/** \internal \returns the reversed elements of \a a*/ +template EIGEN_DEVICE_FUNC inline Packet preverse(const Packet& a) +{ return a; } + +/** \internal \returns \a a with real and imaginary part flipped (for complex type only) */ +template EIGEN_DEVICE_FUNC inline Packet pcplxflip(const Packet& a) +{ + // FIXME: uncomment the following in case we drop the internal imag and real functions. +// using std::imag; +// using std::real; + return Packet(imag(a),real(a)); +} + +/************************** +* Special math functions +***************************/ + +/** \internal \returns the sine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet psin(const Packet& a) { using std::sin; return sin(a); } + +/** \internal \returns the cosine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pcos(const Packet& a) { using std::cos; return cos(a); } + +/** \internal \returns the tan of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet ptan(const Packet& a) { using std::tan; return tan(a); } + +/** \internal \returns the arc sine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pasin(const Packet& a) { using std::asin; return asin(a); } + +/** \internal \returns the arc cosine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pacos(const Packet& a) { using std::acos; return acos(a); } + +/** \internal \returns the arc tangent of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet patan(const Packet& a) { using std::atan; return atan(a); } + +/** \internal \returns the hyperbolic sine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet psinh(const Packet& a) { using std::sinh; return sinh(a); } + +/** \internal \returns the hyperbolic cosine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pcosh(const Packet& a) { using std::cosh; return cosh(a); } + +/** \internal \returns the hyperbolic tan of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet ptanh(const Packet& a) { using std::tanh; return tanh(a); } + +/** \internal \returns the exp of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pexp(const Packet& a) { using std::exp; return exp(a); } + +/** \internal \returns the log of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet plog(const Packet& a) { using std::log; return log(a); } + +/** \internal \returns the log1p of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet plog1p(const Packet& a) { return numext::log1p(a); } + +/** \internal \returns the log10 of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet plog10(const Packet& a) { using std::log10; return log10(a); } + +/** \internal \returns the square-root of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet psqrt(const Packet& a) { using std::sqrt; return sqrt(a); } + +/** \internal \returns the reciprocal square-root of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet prsqrt(const Packet& a) { + return pdiv(pset1(1), psqrt(a)); +} + +/** \internal \returns the rounded value of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pround(const Packet& a) { using numext::round; return round(a); } + +/** \internal \returns the floor of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pfloor(const Packet& a) { using numext::floor; return floor(a); } + +/** \internal \returns the ceil of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pceil(const Packet& a) { using numext::ceil; return ceil(a); } + +/*************************************************************************** +* The following functions might not have to be overwritten for vectorized types +***************************************************************************/ + +/** \internal copy a packet with constant coeficient \a a (e.g., [a,a,a,a]) to \a *to. \a to must be 16 bytes aligned */ +// NOTE: this function must really be templated on the packet type (think about different packet types for the same scalar type) +template +inline void pstore1(typename unpacket_traits::type* to, const typename unpacket_traits::type& a) +{ + pstore(to, pset1(a)); +} + +/** \internal \returns a * b + c (coeff-wise) */ +template EIGEN_DEVICE_FUNC inline Packet +pmadd(const Packet& a, + const Packet& b, + const Packet& c) +{ return padd(pmul(a, b),c); } + +/** \internal \returns a packet version of \a *from. + * The pointer \a from must be aligned on a \a Alignment bytes boundary. */ +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet ploadt(const typename unpacket_traits::type* from) +{ + if(Alignment >= unpacket_traits::alignment) + return pload(from); + else + return ploadu(from); +} + +/** \internal copy the packet \a from to \a *to. + * The pointer \a from must be aligned on a \a Alignment bytes boundary. */ +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void pstoret(Scalar* to, const Packet& from) +{ + if(Alignment >= unpacket_traits::alignment) + pstore(to, from); + else + pstoreu(to, from); +} + +/** \internal \returns a packet version of \a *from. + * Unlike ploadt, ploadt_ro takes advantage of the read-only memory path on the + * hardware if available to speedup the loading of data that won't be modified + * by the current computation. + */ +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet ploadt_ro(const typename unpacket_traits::type* from) +{ + return ploadt(from); +} + +/** \internal default implementation of palign() allowing partial specialization */ +template +struct palign_impl +{ + // by default data are aligned, so there is nothing to be done :) + static inline void run(PacketType&, const PacketType&) {} +}; + +/** \internal update \a first using the concatenation of the packet_size minus \a Offset last elements + * of \a first and \a Offset first elements of \a second. + * + * This function is currently only used to optimize matrix-vector products on unligned matrices. + * It takes 2 packets that represent a contiguous memory array, and returns a packet starting + * at the position \a Offset. For instance, for packets of 4 elements, we have: + * Input: + * - first = {f0,f1,f2,f3} + * - second = {s0,s1,s2,s3} + * Output: + * - if Offset==0 then {f0,f1,f2,f3} + * - if Offset==1 then {f1,f2,f3,s0} + * - if Offset==2 then {f2,f3,s0,s1} + * - if Offset==3 then {f3,s0,s1,s3} + */ +template +inline void palign(PacketType& first, const PacketType& second) +{ + palign_impl::run(first,second); +} + +/*************************************************************************** +* Fast complex products (GCC generates a function call which is very slow) +***************************************************************************/ + +// Eigen+CUDA does not support complexes. +#ifndef __CUDACC__ + +template<> inline std::complex pmul(const std::complex& a, const std::complex& b) +{ return std::complex(real(a)*real(b) - imag(a)*imag(b), imag(a)*real(b) + real(a)*imag(b)); } + +template<> inline std::complex pmul(const std::complex& a, const std::complex& b) +{ return std::complex(real(a)*real(b) - imag(a)*imag(b), imag(a)*real(b) + real(a)*imag(b)); } + +#endif + + +/*************************************************************************** + * PacketBlock, that is a collection of N packets where the number of words + * in the packet is a multiple of N. +***************************************************************************/ +template ::size> struct PacketBlock { + Packet packet[N]; +}; + +template EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& /*kernel*/) { + // Nothing to do in the scalar case, i.e. a 1x1 matrix. +} + +/*************************************************************************** + * Selector, i.e. vector of N boolean values used to select (i.e. blend) + * words from 2 packets. +***************************************************************************/ +template struct Selector { + bool select[N]; +}; + +template EIGEN_DEVICE_FUNC inline Packet +pblend(const Selector::size>& ifPacket, const Packet& thenPacket, const Packet& elsePacket) { + return ifPacket.select[0] ? thenPacket : elsePacket; +} + +/** \internal \returns \a a with the first coefficient replaced by the scalar b */ +template EIGEN_DEVICE_FUNC inline Packet +pinsertfirst(const Packet& a, typename unpacket_traits::type b) +{ + // Default implementation based on pblend. + // It must be specialized for higher performance. + Selector::size> mask; + mask.select[0] = true; + // This for loop should be optimized away by the compiler. + for(Index i=1; i::size; ++i) + mask.select[i] = false; + return pblend(mask, pset1(b), a); +} + +/** \internal \returns \a a with the last coefficient replaced by the scalar b */ +template EIGEN_DEVICE_FUNC inline Packet +pinsertlast(const Packet& a, typename unpacket_traits::type b) +{ + // Default implementation based on pblend. + // It must be specialized for higher performance. + Selector::size> mask; + // This for loop should be optimized away by the compiler. + for(Index i=0; i::size-1; ++i) + mask.select[i] = false; + mask.select[unpacket_traits::size-1] = true; + return pblend(mask, pset1(b), a); +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_GENERIC_PACKET_MATH_H diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/GlobalFunctions.h b/splinter/thirdparty/Eigen/Eigen/src/Core/GlobalFunctions.h new file mode 100644 index 0000000000..769dc255c2 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/GlobalFunctions.h @@ -0,0 +1,187 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010-2016 Gael Guennebaud +// Copyright (C) 2010 Benoit Jacob +// +// 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 + +#ifdef EIGEN_PARSED_BY_DOXYGEN + +#define EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(NAME,FUNCTOR,DOC_OP,DOC_DETAILS) \ + /** \returns an expression of the coefficient-wise DOC_OP of \a x + + DOC_DETAILS + + \sa Math functions, class CwiseUnaryOp + */ \ + template \ + inline const Eigen::CwiseUnaryOp, const Derived> \ + NAME(const Eigen::ArrayBase& x); + +#else + +#define EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(NAME,FUNCTOR,DOC_OP,DOC_DETAILS) \ + template \ + inline const Eigen::CwiseUnaryOp, const Derived> \ + (NAME)(const Eigen::ArrayBase& x) { \ + return Eigen::CwiseUnaryOp, const Derived>(x.derived()); \ + } + +#endif // EIGEN_PARSED_BY_DOXYGEN + +#define EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(NAME,FUNCTOR) \ + \ + template \ + struct NAME##_retval > \ + { \ + typedef const Eigen::CwiseUnaryOp, const Derived> type; \ + }; \ + template \ + struct NAME##_impl > \ + { \ + static inline typename NAME##_retval >::type run(const Eigen::ArrayBase& x) \ + { \ + return typename NAME##_retval >::type(x.derived()); \ + } \ + }; + +namespace Eigen +{ + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(real,scalar_real_op,real part,\sa ArrayBase::real) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(imag,scalar_imag_op,imaginary part,\sa ArrayBase::imag) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(conj,scalar_conjugate_op,complex conjugate,\sa ArrayBase::conjugate) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(inverse,scalar_inverse_op,inverse,\sa ArrayBase::inverse) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sin,scalar_sin_op,sine,\sa ArrayBase::sin) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cos,scalar_cos_op,cosine,\sa ArrayBase::cos) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tan,scalar_tan_op,tangent,\sa ArrayBase::tan) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(atan,scalar_atan_op,arc-tangent,\sa ArrayBase::atan) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(asin,scalar_asin_op,arc-sine,\sa ArrayBase::asin) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(acos,scalar_acos_op,arc-consine,\sa ArrayBase::acos) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sinh,scalar_sinh_op,hyperbolic sine,\sa ArrayBase::sinh) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cosh,scalar_cosh_op,hyperbolic cosine,\sa ArrayBase::cosh) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tanh,scalar_tanh_op,hyperbolic tangent,\sa ArrayBase::tanh) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(lgamma,scalar_lgamma_op,natural logarithm of the gamma function,\sa ArrayBase::lgamma) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(digamma,scalar_digamma_op,derivative of lgamma,\sa ArrayBase::digamma) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(erf,scalar_erf_op,error function,\sa ArrayBase::erf) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(erfc,scalar_erfc_op,complement error function,\sa ArrayBase::erfc) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(exp,scalar_exp_op,exponential,\sa ArrayBase::exp) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log,scalar_log_op,natural logarithm,\sa Eigen::log10 DOXCOMMA ArrayBase::log) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log1p,scalar_log1p_op,natural logarithm of 1 plus the value,\sa ArrayBase::log1p) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log10,scalar_log10_op,base 10 logarithm,\sa Eigen::log DOXCOMMA ArrayBase::log) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs,scalar_abs_op,absolute value,\sa ArrayBase::abs DOXCOMMA MatrixBase::cwiseAbs) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs2,scalar_abs2_op,squared absolute value,\sa ArrayBase::abs2 DOXCOMMA MatrixBase::cwiseAbs2) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(arg,scalar_arg_op,complex argument,\sa ArrayBase::arg) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sqrt,scalar_sqrt_op,square root,\sa ArrayBase::sqrt DOXCOMMA MatrixBase::cwiseSqrt) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(rsqrt,scalar_rsqrt_op,reciprocal square root,\sa ArrayBase::rsqrt) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(square,scalar_square_op,square (power 2),\sa Eigen::abs2 DOXCOMMA Eigen::pow DOXCOMMA ArrayBase::square) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cube,scalar_cube_op,cube (power 3),\sa Eigen::pow DOXCOMMA ArrayBase::cube) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(round,scalar_round_op,nearest integer,\sa Eigen::floor DOXCOMMA Eigen::ceil DOXCOMMA ArrayBase::round) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(floor,scalar_floor_op,nearest integer not greater than the giben value,\sa Eigen::ceil DOXCOMMA ArrayBase::floor) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(ceil,scalar_ceil_op,nearest integer not less than the giben value,\sa Eigen::floor DOXCOMMA ArrayBase::ceil) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isnan,scalar_isnan_op,not-a-number test,\sa Eigen::isinf DOXCOMMA Eigen::isfinite DOXCOMMA ArrayBase::isnan) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isinf,scalar_isinf_op,infinite value test,\sa Eigen::isnan DOXCOMMA Eigen::isfinite DOXCOMMA ArrayBase::isinf) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isfinite,scalar_isfinite_op,finite value test,\sa Eigen::isinf DOXCOMMA Eigen::isnan DOXCOMMA ArrayBase::isfinite) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sign,scalar_sign_op,sign (or 0),\sa ArrayBase::sign) + + /** \returns an expression of the coefficient-wise power of \a x to the given constant \a exponent. + * + * \tparam ScalarExponent is the scalar type of \a exponent. It must be compatible with the scalar type of the given expression (\c Derived::Scalar). + * + * \sa ArrayBase::pow() + * + * \relates ArrayBase + */ +#ifdef EIGEN_PARSED_BY_DOXYGEN + template + inline const CwiseBinaryOp,Derived,Constant > + pow(const Eigen::ArrayBase& x, const ScalarExponent& exponent); +#else + template + inline typename internal::enable_if< !(internal::is_same::value) && EIGEN_SCALAR_BINARY_SUPPORTED(pow,typename Derived::Scalar,ScalarExponent), + const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,ScalarExponent,pow) >::type + pow(const Eigen::ArrayBase& x, const ScalarExponent& exponent) { + return x.derived().pow(exponent); + } + + template + inline const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,typename Derived::Scalar,pow) + pow(const Eigen::ArrayBase& x, const typename Derived::Scalar& exponent) { + return x.derived().pow(exponent); + } +#endif + + /** \returns an expression of the coefficient-wise power of \a x to the given array of \a exponents. + * + * This function computes the coefficient-wise power. + * + * Example: \include Cwise_array_power_array.cpp + * Output: \verbinclude Cwise_array_power_array.out + * + * \sa ArrayBase::pow() + * + * \relates ArrayBase + */ + template + inline const Eigen::CwiseBinaryOp, const Derived, const ExponentDerived> + pow(const Eigen::ArrayBase& x, const Eigen::ArrayBase& exponents) + { + return Eigen::CwiseBinaryOp, const Derived, const ExponentDerived>( + x.derived(), + exponents.derived() + ); + } + + /** \returns an expression of the coefficient-wise power of the scalar \a x to the given array of \a exponents. + * + * This function computes the coefficient-wise power between a scalar and an array of exponents. + * + * \tparam Scalar is the scalar type of \a x. It must be compatible with the scalar type of the given array expression (\c Derived::Scalar). + * + * Example: \include Cwise_scalar_power_array.cpp + * Output: \verbinclude Cwise_scalar_power_array.out + * + * \sa ArrayBase::pow() + * + * \relates ArrayBase + */ +#ifdef EIGEN_PARSED_BY_DOXYGEN + template + inline const CwiseBinaryOp,Constant,Derived> + pow(const Scalar& x,const Eigen::ArrayBase& x); +#else + template + inline typename internal::enable_if< !(internal::is_same::value) && EIGEN_SCALAR_BINARY_SUPPORTED(pow,Scalar,typename Derived::Scalar), + const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(Scalar,Derived,pow) >::type + pow(const Scalar& x, const Eigen::ArrayBase& exponents) + { + return EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(Scalar,Derived,pow)( + typename internal::plain_constant_type::type(exponents.rows(), exponents.cols(), x), exponents.derived() ); + } + + template + inline const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(typename Derived::Scalar,Derived,pow) + pow(const typename Derived::Scalar& x, const Eigen::ArrayBase& exponents) + { + return EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(typename Derived::Scalar,Derived,pow)( + typename internal::plain_constant_type::type(exponents.rows(), exponents.cols(), x), exponents.derived() ); + } +#endif + + + namespace internal + { + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(real,scalar_real_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(imag,scalar_imag_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(abs2,scalar_abs2_op) + } +} + +// TODO: cleanly disable those functions that are not supported on Array (numext::real_ref, internal::random, internal::isApprox...) + +#endif // EIGEN_GLOBAL_FUNCTIONS_H diff --git a/splinter/src/Core/IO.h b/splinter/thirdparty/Eigen/Eigen/src/Core/IO.h similarity index 85% rename from splinter/src/Core/IO.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/IO.h index 8d4bc59e9d..da7fd6cce2 100644 --- a/splinter/src/Core/IO.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/IO.h @@ -49,7 +49,7 @@ std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& */ struct IOFormat { - /** Default contructor, see class IOFormat for the meaning of the parameters */ + /** Default constructor, see class IOFormat for the meaning of the parameters */ IOFormat(int _precision = StreamPrecision, int _flags = 0, const std::string& _coeffSeparator = " ", const std::string& _rowSeparator = "\n", const std::string& _rowPrefix="", const std::string& _rowSuffix="", @@ -57,6 +57,10 @@ struct IOFormat : matPrefix(_matPrefix), matSuffix(_matSuffix), rowPrefix(_rowPrefix), rowSuffix(_rowSuffix), rowSeparator(_rowSeparator), rowSpacer(""), coeffSeparator(_coeffSeparator), precision(_precision), flags(_flags) { + // TODO check if rowPrefix, rowSuffix or rowSeparator contains a newline + // don't add rowSpacer if columns are not to be aligned + if((flags & DontAlignCols)) + return; int i = int(matSuffix.length())-1; while (i>=0 && matSuffix[i]!='\n') { @@ -76,7 +80,7 @@ struct IOFormat * * \brief Pseudo expression providing matrix output with given format * - * \param ExpressionType the type of the object on which IO stream operations are performed + * \tparam ExpressionType the type of the object on which IO stream operations are performed * * This class represents an expression with stream operators controlled by a given IOFormat. * It is the return type of DenseBase::format() @@ -101,52 +105,24 @@ class WithFormat } protected: - const typename ExpressionType::Nested m_matrix; + typename ExpressionType::Nested m_matrix; IOFormat m_format; }; -/** \returns a WithFormat proxy object allowing to print a matrix the with given - * format \a fmt. - * - * See class IOFormat for some examples. - * - * \sa class IOFormat, class WithFormat - */ -template -inline const WithFormat -DenseBase::format(const IOFormat& fmt) const -{ - return WithFormat(derived(), fmt); -} - namespace internal { -template -struct significant_decimals_default_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline int run() - { - using std::ceil; - using std::log; - return cast(ceil(-log(NumTraits::epsilon())/log(RealScalar(10)))); - } -}; - +// NOTE: This helper is kept for backward compatibility with previous code specializing +// this internal::significant_decimals_impl structure. In the future we should directly +// call digits10() which has been introduced in July 2016 in 3.3. template -struct significant_decimals_default_impl +struct significant_decimals_impl { static inline int run() { - return 0; + return NumTraits::digits10(); } }; -template -struct significant_decimals_impl - : significant_decimals_default_impl::IsInteger> -{}; - /** \internal * print the matrix \a _m to the output stream \a s using the output format \a fmt */ template @@ -160,7 +136,6 @@ std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& typename Derived::Nested m = _m; typedef typename Derived::Scalar Scalar; - typedef typename Derived::Index Index; Index width = 0; diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/Inverse.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Inverse.h new file mode 100644 index 0000000000..b76f0439d8 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Inverse.h @@ -0,0 +1,118 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 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_INVERSE_H +#define EIGEN_INVERSE_H + +namespace Eigen { + +template class InverseImpl; + +namespace internal { + +template +struct traits > + : traits +{ + typedef typename XprType::PlainObject PlainObject; + typedef traits BaseTraits; + enum { + Flags = BaseTraits::Flags & RowMajorBit + }; +}; + +} // end namespace internal + +/** \class Inverse + * + * \brief Expression of the inverse of another expression + * + * \tparam XprType the type of the expression we are taking the inverse + * + * This class represents an abstract expression of A.inverse() + * and most of the time this is the only way it is used. + * + */ +template +class Inverse : public InverseImpl::StorageKind> +{ +public: + typedef typename XprType::StorageIndex StorageIndex; + typedef typename XprType::PlainObject PlainObject; + typedef typename XprType::Scalar Scalar; + typedef typename internal::ref_selector::type XprTypeNested; + typedef typename internal::remove_all::type XprTypeNestedCleaned; + typedef typename internal::ref_selector::type Nested; + typedef typename internal::remove_all::type NestedExpression; + + explicit EIGEN_DEVICE_FUNC Inverse(const XprType &xpr) + : m_xpr(xpr) + {} + + EIGEN_DEVICE_FUNC Index rows() const { return m_xpr.rows(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_xpr.cols(); } + + EIGEN_DEVICE_FUNC const XprTypeNestedCleaned& nestedExpression() const { return m_xpr; } + +protected: + XprTypeNested m_xpr; +}; + +// Generic API dispatcher +template +class InverseImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; + typedef typename XprType::Scalar Scalar; +private: + + Scalar coeff(Index row, Index col) const; + Scalar coeff(Index i) const; +}; + +namespace internal { + +/** \internal + * \brief Default evaluator for Inverse expression. + * + * This default evaluator for Inverse expression simply evaluate the inverse into a temporary + * by a call to internal::call_assignment_no_alias. + * Therefore, inverse implementers only have to specialize Assignment, ...> for + * there own nested expression. + * + * \sa class Inverse + */ +template +struct unary_evaluator > + : public evaluator::PlainObject> +{ + typedef Inverse InverseType; + typedef typename InverseType::PlainObject PlainObject; + typedef evaluator Base; + + enum { Flags = Base::Flags | EvalBeforeNestingBit }; + + unary_evaluator(const InverseType& inv_xpr) + : m_result(inv_xpr.rows(), inv_xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + internal::call_assignment_no_alias(m_result, inv_xpr); + } + +protected: + PlainObject m_result; +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_INVERSE_H diff --git a/splinter/src/Core/Map.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Map.h similarity index 62% rename from splinter/src/Core/Map.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/Map.h index f804c89d63..548bf9a2d5 100644 --- a/splinter/src/Core/Map.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Map.h @@ -13,13 +13,41 @@ namespace Eigen { +namespace internal { +template +struct traits > + : public traits +{ + typedef traits TraitsBase; + enum { + PlainObjectTypeInnerSize = ((traits::Flags&RowMajorBit)==RowMajorBit) + ? PlainObjectType::ColsAtCompileTime + : PlainObjectType::RowsAtCompileTime, + + InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 + ? int(PlainObjectType::InnerStrideAtCompileTime) + : int(StrideType::InnerStrideAtCompileTime), + OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 + ? (InnerStrideAtCompileTime==Dynamic || PlainObjectTypeInnerSize==Dynamic + ? Dynamic + : int(InnerStrideAtCompileTime) * int(PlainObjectTypeInnerSize)) + : int(StrideType::OuterStrideAtCompileTime), + Alignment = int(MapOptions)&int(AlignedMask), + Flags0 = TraitsBase::Flags & (~NestByRefBit), + Flags = is_lvalue::value ? int(Flags0) : (int(Flags0) & ~LvalueBit) + }; +private: + enum { Options }; // Expressions don't have Options +}; +} + /** \class Map * \ingroup Core_Module * * \brief A matrix or vector expression mapping an existing array of data. * * \tparam PlainObjectType the equivalent matrix type of the mapped data - * \tparam MapOptions specifies whether the pointer is \c #Aligned, or \c #Unaligned. + * \tparam MapOptions specifies the pointer alignment in bytes. It can be: \c #Aligned128, , \c #Aligned64, \c #Aligned32, \c #Aligned16, \c #Aligned8 or \c #Unaligned. * The default is \c #Unaligned. * \tparam StrideType optionally specifies strides. By default, Map assumes the memory layout * of an ordinary, contiguous array. This can be overridden by specifying strides. @@ -63,44 +91,6 @@ namespace Eigen { * * \sa PlainObjectBase::Map(), \ref TopicStorageOrders */ - -namespace internal { -template -struct traits > - : public traits -{ - typedef traits TraitsBase; - typedef typename PlainObjectType::Index Index; - typedef typename PlainObjectType::Scalar Scalar; - enum { - InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 - ? int(PlainObjectType::InnerStrideAtCompileTime) - : int(StrideType::InnerStrideAtCompileTime), - OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 - ? int(PlainObjectType::OuterStrideAtCompileTime) - : int(StrideType::OuterStrideAtCompileTime), - HasNoInnerStride = InnerStrideAtCompileTime == 1, - HasNoOuterStride = StrideType::OuterStrideAtCompileTime == 0, - HasNoStride = HasNoInnerStride && HasNoOuterStride, - IsAligned = bool(EIGEN_ALIGN) && ((int(MapOptions)&Aligned)==Aligned), - IsDynamicSize = PlainObjectType::SizeAtCompileTime==Dynamic, - KeepsPacketAccess = bool(HasNoInnerStride) - && ( bool(IsDynamicSize) - || HasNoOuterStride - || ( OuterStrideAtCompileTime!=Dynamic - && ((static_cast(sizeof(Scalar))*OuterStrideAtCompileTime)%16)==0 ) ), - Flags0 = TraitsBase::Flags & (~NestByRefBit), - Flags1 = IsAligned ? (int(Flags0) | AlignedBit) : (int(Flags0) & ~AlignedBit), - Flags2 = (bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime)) - ? int(Flags1) : int(Flags1 & ~LinearAccessBit), - Flags3 = is_lvalue::value ? int(Flags2) : (int(Flags2) & ~LvalueBit), - Flags = KeepsPacketAccess ? int(Flags3) : (int(Flags3) & ~PacketAccessBit) - }; -private: - enum { Options }; // Expressions don't have Options -}; -} - template class Map : public MapBase > { @@ -110,34 +100,34 @@ template class Ma EIGEN_DENSE_PUBLIC_INTERFACE(Map) typedef typename Base::PointerType PointerType; -#if EIGEN2_SUPPORT_STAGE <= STAGE30_FULL_EIGEN3_API - typedef const Scalar* PointerArgType; - inline PointerType cast_to_pointer_type(PointerArgType ptr) { return const_cast(ptr); } -#else typedef PointerType PointerArgType; + EIGEN_DEVICE_FUNC inline PointerType cast_to_pointer_type(PointerArgType ptr) { return ptr; } -#endif + EIGEN_DEVICE_FUNC inline Index innerStride() const { return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; } + EIGEN_DEVICE_FUNC inline Index outerStride() const { - return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer() - : IsVectorAtCompileTime ? this->size() - : int(Flags)&RowMajorBit ? this->cols() - : this->rows(); + return int(StrideType::OuterStrideAtCompileTime) != 0 ? m_stride.outer() + : int(internal::traits::OuterStrideAtCompileTime) != Dynamic ? Index(internal::traits::OuterStrideAtCompileTime) + : IsVectorAtCompileTime ? (this->size() * innerStride()) + : (int(Flags)&RowMajorBit) ? (this->cols() * innerStride()) + : (this->rows() * innerStride()); } /** Constructor in the fixed-size case. * * \param dataPtr pointer to the array to map - * \param a_stride optional Stride object, passing the strides. + * \param stride optional Stride object, passing the strides. */ - inline Map(PointerArgType dataPtr, const StrideType& a_stride = StrideType()) - : Base(cast_to_pointer_type(dataPtr)), m_stride(a_stride) + EIGEN_DEVICE_FUNC + explicit inline Map(PointerArgType dataPtr, const StrideType& stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr)), m_stride(stride) { PlainObjectType::Base::_check_template_params(); } @@ -145,11 +135,12 @@ template class Ma /** Constructor in the dynamic-size vector case. * * \param dataPtr pointer to the array to map - * \param a_size the size of the vector expression - * \param a_stride optional Stride object, passing the strides. + * \param size the size of the vector expression + * \param stride optional Stride object, passing the strides. */ - inline Map(PointerArgType dataPtr, Index a_size, const StrideType& a_stride = StrideType()) - : Base(cast_to_pointer_type(dataPtr), a_size), m_stride(a_stride) + EIGEN_DEVICE_FUNC + inline Map(PointerArgType dataPtr, Index size, const StrideType& stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr), size), m_stride(stride) { PlainObjectType::Base::_check_template_params(); } @@ -157,12 +148,13 @@ template class Ma /** Constructor in the dynamic-size matrix case. * * \param dataPtr pointer to the array to map - * \param nbRows the number of rows of the matrix expression - * \param nbCols the number of columns of the matrix expression - * \param a_stride optional Stride object, passing the strides. + * \param rows the number of rows of the matrix expression + * \param cols the number of columns of the matrix expression + * \param stride optional Stride object, passing the strides. */ - inline Map(PointerArgType dataPtr, Index nbRows, Index nbCols, const StrideType& a_stride = StrideType()) - : Base(cast_to_pointer_type(dataPtr), nbRows, nbCols), m_stride(a_stride) + EIGEN_DEVICE_FUNC + inline Map(PointerArgType dataPtr, Index rows, Index cols, const StrideType& stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr), rows, cols), m_stride(stride) { PlainObjectType::Base::_check_template_params(); } @@ -173,19 +165,6 @@ template class Ma StrideType m_stride; }; -template -inline Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> - ::Array(const Scalar *data) -{ - this->_set_noalias(Eigen::Map(data)); -} - -template -inline Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> - ::Matrix(const Scalar *data) -{ - this->_set_noalias(Eigen::Map(data)); -} } // end namespace Eigen diff --git a/splinter/src/Core/MapBase.h b/splinter/thirdparty/Eigen/Eigen/src/Core/MapBase.h similarity index 66% rename from splinter/src/Core/MapBase.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/MapBase.h index 81efc4a6d5..020f939ad6 100644 --- a/splinter/src/Core/MapBase.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/MapBase.h @@ -12,15 +12,25 @@ #define EIGEN_MAPBASE_H #define EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) \ - EIGEN_STATIC_ASSERT((int(internal::traits::Flags) & LinearAccessBit) || Derived::IsVectorAtCompileTime, \ + EIGEN_STATIC_ASSERT((int(internal::evaluator::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 +/** \ingroup Core_Module * - * \brief Base class for Map and Block expression with direct access + * \brief Base class for dense Map and Block expression with direct access + * + * This base class provides the const low-level accessors (e.g. coeff, coeffRef) of dense + * Map and Block objects with direct access. + * Typical users do not have to directly deal with this class. + * + * This class can be extended by through the macro plugin \c EIGEN_MAPBASE_PLUGIN. + * See \link TopicCustomizing_Plugins customizing Eigen \endlink for details. + * + * The \c Derived class has to provide the following two methods describing the memory layout: + * \code Index innerStride() const; \endcode + * \code Index outerStride() const; \endcode * * \sa class Map, class Block */ @@ -37,7 +47,6 @@ template class MapBase }; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; @@ -76,8 +85,10 @@ template class MapBase typedef typename Base::CoeffReturnType CoeffReturnType; - inline Index rows() const { return m_rows.value(); } - inline Index cols() const { return m_cols.value(); } + /** \copydoc DenseBase::rows() */ + EIGEN_DEVICE_FUNC inline Index rows() const { return m_rows.value(); } + /** \copydoc DenseBase::cols() */ + EIGEN_DEVICE_FUNC inline Index cols() const { return m_cols.value(); } /** Returns a pointer to the first coefficient of the matrix or vector. * @@ -85,30 +96,39 @@ template class MapBase * * \sa innerStride(), outerStride() */ - inline const Scalar* data() const { return m_data; } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return m_data; } + /** \copydoc PlainObjectBase::coeff(Index,Index) const */ + EIGEN_DEVICE_FUNC inline const Scalar& coeff(Index rowId, Index colId) const { return m_data[colId * colStride() + rowId * rowStride()]; } + /** \copydoc PlainObjectBase::coeff(Index) const */ + EIGEN_DEVICE_FUNC inline const Scalar& coeff(Index index) const { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) return m_data[index * innerStride()]; } + /** \copydoc PlainObjectBase::coeffRef(Index,Index) const */ + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const { return this->m_data[colId * colStride() + rowId * rowStride()]; } + /** \copydoc PlainObjectBase::coeffRef(Index) const */ + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) return this->m_data[index * innerStride()]; } + /** \internal */ template inline PacketScalar packet(Index rowId, Index colId) const { @@ -116,6 +136,7 @@ template class MapBase (m_data + (colId * colStride() + rowId * rowStride())); } + /** \internal */ template inline PacketScalar packet(Index index) const { @@ -123,12 +144,16 @@ template class MapBase return internal::ploadt(m_data + index * innerStride()); } + /** \internal Constructor for fixed size matrices or vectors */ + EIGEN_DEVICE_FUNC explicit inline MapBase(PointerType dataPtr) : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) { EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) - checkSanity(); + checkSanity(); } + /** \internal Constructor for dynamically sized vectors */ + EIGEN_DEVICE_FUNC inline MapBase(PointerType dataPtr, Index vecSize) : m_data(dataPtr), m_rows(RowsAtCompileTime == Dynamic ? vecSize : Index(RowsAtCompileTime)), @@ -137,16 +162,18 @@ template class MapBase EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) eigen_assert(vecSize >= 0); eigen_assert(dataPtr == 0 || SizeAtCompileTime == Dynamic || SizeAtCompileTime == vecSize); - checkSanity(); + checkSanity(); } - inline MapBase(PointerType dataPtr, Index nbRows, Index nbCols) - : m_data(dataPtr), m_rows(nbRows), m_cols(nbCols) + /** \internal Constructor for dynamically sized matrices */ + EIGEN_DEVICE_FUNC + inline MapBase(PointerType dataPtr, Index rows, Index cols) + : m_data(dataPtr), m_rows(rows), m_cols(cols) { eigen_assert( (dataPtr == 0) - || ( nbRows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == nbRows) - && nbCols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == nbCols))); - checkSanity(); + || ( rows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows) + && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols))); + checkSanity(); } #ifdef EIGEN_MAPBASE_PLUGIN @@ -155,20 +182,36 @@ template class MapBase protected: - void checkSanity() const + template + EIGEN_DEVICE_FUNC + void checkSanity(typename internal::enable_if<(internal::traits::Alignment>0),void*>::type = 0) const { - EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(internal::traits::Flags&PacketAccessBit, - internal::inner_stride_at_compile_time::ret==1), - PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); - eigen_assert(EIGEN_IMPLIES(internal::traits::Flags&AlignedBit, (size_t(m_data) % 16) == 0) - && "input pointer is not aligned on a 16 byte boundary"); +#if EIGEN_MAX_ALIGN_BYTES>0 + eigen_assert(( ((internal::UIntPtr(m_data) % internal::traits::Alignment) == 0) + || (cols() * rows() * innerStride() * sizeof(Scalar)) < internal::traits::Alignment ) && "data is not aligned"); +#endif } + template + EIGEN_DEVICE_FUNC + void checkSanity(typename internal::enable_if::Alignment==0,void*>::type = 0) const + {} + PointerType m_data; const internal::variable_if_dynamic m_rows; const internal::variable_if_dynamic m_cols; }; +/** \ingroup Core_Module + * + * \brief Base class for non-const dense Map and Block expression with direct access + * + * This base class provides the non-const low-level accessors (e.g. coeff and coeffRef) of + * dense Map and Block objects with direct access. + * It inherits MapBase which defines the const variant for reading specific entries. + * + * \sa class Map, class Block + */ template class MapBase : public MapBase { @@ -179,7 +222,7 @@ template class MapBase typedef typename Base::Scalar Scalar; typedef typename Base::PacketScalar PacketScalar; - typedef typename Base::Index Index; + typedef typename Base::StorageIndex StorageIndex; typedef typename Base::PointerType PointerType; using Base::derived; @@ -200,14 +243,18 @@ template class MapBase const Scalar >::type ScalarWithConstIfNotLvalue; + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return this->m_data; } + EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue* data() { return this->m_data; } // no const-cast here so non-const-correct code will give a compile error + EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue& coeffRef(Index row, Index col) { return this->m_data[col * colStride() + row * rowStride()]; } + EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue& coeffRef(Index index) { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) @@ -229,10 +276,11 @@ template class MapBase (this->m_data + index * innerStride(), val); } - explicit inline MapBase(PointerType dataPtr) : Base(dataPtr) {} - inline MapBase(PointerType dataPtr, Index vecSize) : Base(dataPtr, vecSize) {} - inline MapBase(PointerType dataPtr, Index nbRows, Index nbCols) : Base(dataPtr, nbRows, nbCols) {} + EIGEN_DEVICE_FUNC explicit inline MapBase(PointerType dataPtr) : Base(dataPtr) {} + EIGEN_DEVICE_FUNC inline MapBase(PointerType dataPtr, Index vecSize) : Base(dataPtr, vecSize) {} + EIGEN_DEVICE_FUNC inline MapBase(PointerType dataPtr, Index rows, Index cols) : Base(dataPtr, rows, cols) {} + EIGEN_DEVICE_FUNC Derived& operator=(const MapBase& other) { ReadOnlyMapBase::Base::operator=(other); diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/MathFunctions.h b/splinter/thirdparty/Eigen/Eigen/src/Core/MathFunctions.h new file mode 100644 index 0000000000..6eb974d41d --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/MathFunctions.h @@ -0,0 +1,1407 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2010 Benoit Jacob +// +// 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 + +// source: http://www.geom.uiuc.edu/~huberty/math5337/groupe/digits.html +// TODO this should better be moved to NumTraits +#define EIGEN_PI 3.141592653589793238462643383279502884197169399375105820974944592307816406L + + +namespace Eigen { + +// On WINCE, std::abs is defined for int only, so let's defined our own overloads: +// This issue has been confirmed with MSVC 2008 only, but the issue might exist for more recent versions too. +#if EIGEN_OS_WINCE && EIGEN_COMP_MSVC && EIGEN_COMP_MSVC<=1500 +long abs(long x) { return (labs(x)); } +double abs(double x) { return (fabs(x)); } +float abs(float x) { return (fabsf(x)); } +long double abs(long double x) { return (fabsl(x)); } +#endif + +namespace internal { + +/** \internal \class global_math_functions_filtering_base + * + * What it does: + * Defines a typedef 'type' as follows: + * - if type T has a member typedef Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl, then + * global_math_functions_filtering_base::type is a typedef for it. + * - otherwise, global_math_functions_filtering_base::type is a typedef for T. + * + * How it's used: + * To allow to defined the global math functions (like sin...) in certain cases, like the Array expressions. + * When you do sin(array1+array2), the object array1+array2 has a complicated expression type, all what you want to know + * is that it inherits ArrayBase. So we implement a partial specialization of sin_impl for ArrayBase. + * So we must make sure to use sin_impl > and not sin_impl, otherwise our partial specialization + * won't be used. How does sin know that? That's exactly what global_math_functions_filtering_base tells it. + * + * How it's implemented: + * SFINAE in the style of enable_if. Highly susceptible of breaking compilers. With GCC, it sure does work, but if you replace + * the typename dummy by an integer template parameter, it doesn't work anymore! + */ + +template +struct global_math_functions_filtering_base +{ + typedef T type; +}; + +template struct always_void { typedef void type; }; + +template +struct global_math_functions_filtering_base + ::type + > +{ + typedef typename T::Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl type; +}; + +#define EIGEN_MATHFUNC_IMPL(func, scalar) Eigen::internal::func##_impl::type> +#define EIGEN_MATHFUNC_RETVAL(func, scalar) typename Eigen::internal::func##_retval::type>::type + +/**************************************************************************** +* Implementation of real * +****************************************************************************/ + +template::IsComplex> +struct real_default_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + return x; + } +}; + +template +struct real_default_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + using std::real; + return real(x); + } +}; + +template struct real_impl : real_default_impl {}; + +#ifdef __CUDA_ARCH__ +template +struct real_impl > +{ + typedef T RealScalar; + EIGEN_DEVICE_FUNC + static inline T run(const std::complex& x) + { + return x.real(); + } +}; +#endif + +template +struct real_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of imag * +****************************************************************************/ + +template::IsComplex> +struct imag_default_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar&) + { + return RealScalar(0); + } +}; + +template +struct imag_default_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + using std::imag; + return imag(x); + } +}; + +template struct imag_impl : imag_default_impl {}; + +#ifdef __CUDA_ARCH__ +template +struct imag_impl > +{ + typedef T RealScalar; + EIGEN_DEVICE_FUNC + static inline T run(const std::complex& x) + { + return x.imag(); + } +}; +#endif + +template +struct imag_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of real_ref * +****************************************************************************/ + +template +struct real_ref_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar& run(Scalar& x) + { + return reinterpret_cast(&x)[0]; + } + EIGEN_DEVICE_FUNC + static inline const RealScalar& run(const Scalar& x) + { + return reinterpret_cast(&x)[0]; + } +}; + +template +struct real_ref_retval +{ + typedef typename NumTraits::Real & type; +}; + +/**************************************************************************** +* Implementation of imag_ref * +****************************************************************************/ + +template +struct imag_ref_default_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar& run(Scalar& x) + { + return reinterpret_cast(&x)[1]; + } + EIGEN_DEVICE_FUNC + static inline const RealScalar& run(const Scalar& x) + { + return reinterpret_cast(&x)[1]; + } +}; + +template +struct imag_ref_default_impl +{ + EIGEN_DEVICE_FUNC + static inline Scalar run(Scalar&) + { + return Scalar(0); + } + EIGEN_DEVICE_FUNC + static inline const Scalar run(const Scalar&) + { + return Scalar(0); + } +}; + +template +struct imag_ref_impl : imag_ref_default_impl::IsComplex> {}; + +template +struct imag_ref_retval +{ + typedef typename NumTraits::Real & type; +}; + +/**************************************************************************** +* Implementation of conj * +****************************************************************************/ + +template::IsComplex> +struct conj_impl +{ + EIGEN_DEVICE_FUNC + static inline Scalar run(const Scalar& x) + { + return x; + } +}; + +template +struct conj_impl +{ + EIGEN_DEVICE_FUNC + static inline Scalar run(const Scalar& x) + { + using std::conj; + return conj(x); + } +}; + +template +struct conj_retval +{ + typedef Scalar type; +}; + +/**************************************************************************** +* Implementation of abs2 * +****************************************************************************/ + +template +struct abs2_impl_default +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + return x*x; + } +}; + +template +struct abs2_impl_default // IsComplex +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + return real(x)*real(x) + imag(x)*imag(x); + } +}; + +template +struct abs2_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + return abs2_impl_default::IsComplex>::run(x); + } +}; + +template +struct abs2_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of norm1 * +****************************************************************************/ + +template +struct norm1_default_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + EIGEN_USING_STD_MATH(abs); + return abs(real(x)) + abs(imag(x)); + } +}; + +template +struct norm1_default_impl +{ + EIGEN_DEVICE_FUNC + static inline Scalar run(const Scalar& x) + { + EIGEN_USING_STD_MATH(abs); + return abs(x); + } +}; + +template +struct norm1_impl : norm1_default_impl::IsComplex> {}; + +template +struct norm1_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of hypot * +****************************************************************************/ + +template struct hypot_impl; + +template +struct hypot_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of cast * +****************************************************************************/ + +template +struct cast_impl +{ + EIGEN_DEVICE_FUNC + static inline NewType run(const OldType& x) + { + return static_cast(x); + } +}; + +// here, for once, we're plainly returning NewType: we don't want cast to do weird things. + +template +EIGEN_DEVICE_FUNC +inline NewType cast(const OldType& x) +{ + return cast_impl::run(x); +} + +/**************************************************************************** +* Implementation of round * +****************************************************************************/ + +#if EIGEN_HAS_CXX11_MATH + template + struct round_impl { + static inline Scalar run(const Scalar& x) + { + EIGEN_STATIC_ASSERT((!NumTraits::IsComplex), NUMERIC_TYPE_MUST_BE_REAL) + using std::round; + return round(x); + } + }; +#else + template + struct round_impl + { + static inline Scalar run(const Scalar& x) + { + EIGEN_STATIC_ASSERT((!NumTraits::IsComplex), NUMERIC_TYPE_MUST_BE_REAL) + EIGEN_USING_STD_MATH(floor); + EIGEN_USING_STD_MATH(ceil); + return (x > Scalar(0)) ? floor(x + Scalar(0.5)) : ceil(x - Scalar(0.5)); + } + }; +#endif + +template +struct round_retval +{ + typedef Scalar type; +}; + +/**************************************************************************** +* Implementation of arg * +****************************************************************************/ + +#if EIGEN_HAS_CXX11_MATH + template + struct arg_impl { + static inline Scalar run(const Scalar& x) + { + EIGEN_USING_STD_MATH(arg); + return arg(x); + } + }; +#else + template::IsComplex> + struct arg_default_impl + { + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + return (x < Scalar(0)) ? Scalar(EIGEN_PI) : Scalar(0); } + }; + + template + struct arg_default_impl + { + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + EIGEN_USING_STD_MATH(arg); + return arg(x); + } + }; + + template struct arg_impl : arg_default_impl {}; +#endif + +template +struct arg_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of log1p * +****************************************************************************/ + +namespace std_fallback { + // fallback log1p implementation in case there is no log1p(Scalar) function in namespace of Scalar, + // or that there is no suitable std::log1p function available + template + EIGEN_DEVICE_FUNC inline Scalar log1p(const Scalar& x) { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + typedef typename NumTraits::Real RealScalar; + EIGEN_USING_STD_MATH(log); + Scalar x1p = RealScalar(1) + x; + return numext::equal_strict(x1p, Scalar(1)) ? x : x * ( log(x1p) / (x1p - RealScalar(1)) ); + } +} + +template +struct log1p_impl { + static inline Scalar run(const Scalar& x) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + #if EIGEN_HAS_CXX11_MATH + using std::log1p; + #endif + using std_fallback::log1p; + return log1p(x); + } +}; + + +template +struct log1p_retval +{ + typedef Scalar type; +}; + +/**************************************************************************** +* Implementation of pow * +****************************************************************************/ + +template::IsInteger&&NumTraits::IsInteger> +struct pow_impl +{ + //typedef Scalar retval; + typedef typename ScalarBinaryOpTraits >::ReturnType result_type; + static EIGEN_DEVICE_FUNC inline result_type run(const ScalarX& x, const ScalarY& y) + { + EIGEN_USING_STD_MATH(pow); + return pow(x, y); + } +}; + +template +struct pow_impl +{ + typedef ScalarX result_type; + static EIGEN_DEVICE_FUNC inline ScalarX run(ScalarX x, ScalarY y) + { + ScalarX res(1); + eigen_assert(!NumTraits::IsSigned || y >= 0); + if(y & 1) res *= x; + y >>= 1; + while(y) + { + x *= x; + if(y&1) res *= x; + y >>= 1; + } + return res; + } +}; + +/**************************************************************************** +* Implementation of random * +****************************************************************************/ + +template +struct random_default_impl {}; + +template +struct random_impl : random_default_impl::IsComplex, NumTraits::IsInteger> {}; + +template +struct random_retval +{ + typedef Scalar type; +}; + +template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y); +template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(); + +template +struct random_default_impl +{ + static inline Scalar run(const Scalar& x, const Scalar& y) + { + return x + (y-x) * Scalar(std::rand()) / Scalar(RAND_MAX); + } + static inline Scalar run() + { + return run(Scalar(NumTraits::IsSigned ? -1 : 0), Scalar(1)); + } +}; + +enum { + meta_floor_log2_terminate, + meta_floor_log2_move_up, + meta_floor_log2_move_down, + meta_floor_log2_bogus +}; + +template struct meta_floor_log2_selector +{ + enum { middle = (lower + upper) / 2, + value = (upper <= lower + 1) ? int(meta_floor_log2_terminate) + : (n < (1 << middle)) ? int(meta_floor_log2_move_down) + : (n==0) ? int(meta_floor_log2_bogus) + : int(meta_floor_log2_move_up) + }; +}; + +template::value> +struct meta_floor_log2 {}; + +template +struct meta_floor_log2 +{ + enum { value = meta_floor_log2::middle>::value }; +}; + +template +struct meta_floor_log2 +{ + enum { value = meta_floor_log2::middle, upper>::value }; +}; + +template +struct meta_floor_log2 +{ + enum { value = (n >= ((unsigned int)(1) << (lower+1))) ? lower+1 : lower }; +}; + +template +struct meta_floor_log2 +{ + // no value, error at compile time +}; + +template +struct random_default_impl +{ + static inline Scalar run(const Scalar& x, const Scalar& y) + { + typedef typename conditional::IsSigned,std::ptrdiff_t,std::size_t>::type ScalarX; + if(y=x the result converted to an unsigned long is still correct. + std::size_t range = ScalarX(y)-ScalarX(x); + std::size_t offset = 0; + // rejection sampling + std::size_t divisor = 1; + std::size_t multiplier = 1; + if(range range); + return Scalar(ScalarX(x) + offset); + } + + static inline Scalar run() + { +#ifdef EIGEN_MAKING_DOCS + return run(Scalar(NumTraits::IsSigned ? -10 : 0), Scalar(10)); +#else + enum { rand_bits = meta_floor_log2<(unsigned int)(RAND_MAX)+1>::value, + scalar_bits = sizeof(Scalar) * CHAR_BIT, + shift = EIGEN_PLAIN_ENUM_MAX(0, int(rand_bits) - int(scalar_bits)), + offset = NumTraits::IsSigned ? (1 << (EIGEN_PLAIN_ENUM_MIN(rand_bits,scalar_bits)-1)) : 0 + }; + return Scalar((std::rand() >> shift) - offset); +#endif + } +}; + +template +struct random_default_impl +{ + static inline Scalar run(const Scalar& x, const Scalar& y) + { + return Scalar(random(real(x), real(y)), + random(imag(x), imag(y))); + } + static inline Scalar run() + { + typedef typename NumTraits::Real RealScalar; + return Scalar(random(), random()); + } +}; + +template +inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y) +{ + return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(x, y); +} + +template +inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random() +{ + return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(); +} + +// Implementatin of is* functions + +// std::is* do not work with fast-math and gcc, std::is* are available on MSVC 2013 and newer, as well as in clang. +#if (EIGEN_HAS_CXX11_MATH && !(EIGEN_COMP_GNUC_STRICT && __FINITE_MATH_ONLY__)) || (EIGEN_COMP_MSVC>=1800) || (EIGEN_COMP_CLANG) +#define EIGEN_USE_STD_FPCLASSIFY 1 +#else +#define EIGEN_USE_STD_FPCLASSIFY 0 +#endif + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if::value,bool>::type +isnan_impl(const T&) { return false; } + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if::value,bool>::type +isinf_impl(const T&) { return false; } + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if::value,bool>::type +isfinite_impl(const T&) { return true; } + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if<(!internal::is_integral::value)&&(!NumTraits::IsComplex),bool>::type +isfinite_impl(const T& x) +{ + #ifdef __CUDA_ARCH__ + return (::isfinite)(x); + #elif EIGEN_USE_STD_FPCLASSIFY + using std::isfinite; + return isfinite EIGEN_NOT_A_MACRO (x); + #else + return x<=NumTraits::highest() && x>=NumTraits::lowest(); + #endif +} + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if<(!internal::is_integral::value)&&(!NumTraits::IsComplex),bool>::type +isinf_impl(const T& x) +{ + #ifdef __CUDA_ARCH__ + return (::isinf)(x); + #elif EIGEN_USE_STD_FPCLASSIFY + using std::isinf; + return isinf EIGEN_NOT_A_MACRO (x); + #else + return x>NumTraits::highest() || x::lowest(); + #endif +} + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if<(!internal::is_integral::value)&&(!NumTraits::IsComplex),bool>::type +isnan_impl(const T& x) +{ + #ifdef __CUDA_ARCH__ + return (::isnan)(x); + #elif EIGEN_USE_STD_FPCLASSIFY + using std::isnan; + return isnan EIGEN_NOT_A_MACRO (x); + #else + return x != x; + #endif +} + +#if (!EIGEN_USE_STD_FPCLASSIFY) + +#if EIGEN_COMP_MSVC + +template EIGEN_DEVICE_FUNC bool isinf_msvc_helper(T x) +{ + return _fpclass(x)==_FPCLASS_NINF || _fpclass(x)==_FPCLASS_PINF; +} + +//MSVC defines a _isnan builtin function, but for double only +EIGEN_DEVICE_FUNC inline bool isnan_impl(const long double& x) { return _isnan(x)!=0; } +EIGEN_DEVICE_FUNC inline bool isnan_impl(const double& x) { return _isnan(x)!=0; } +EIGEN_DEVICE_FUNC inline bool isnan_impl(const float& x) { return _isnan(x)!=0; } + +EIGEN_DEVICE_FUNC inline bool isinf_impl(const long double& x) { return isinf_msvc_helper(x); } +EIGEN_DEVICE_FUNC inline bool isinf_impl(const double& x) { return isinf_msvc_helper(x); } +EIGEN_DEVICE_FUNC inline bool isinf_impl(const float& x) { return isinf_msvc_helper(x); } + +#elif (defined __FINITE_MATH_ONLY__ && __FINITE_MATH_ONLY__ && EIGEN_COMP_GNUC) + +#if EIGEN_GNUC_AT_LEAST(5,0) + #define EIGEN_TMP_NOOPT_ATTRIB EIGEN_DEVICE_FUNC inline __attribute__((optimize("no-finite-math-only"))) +#else + // NOTE the inline qualifier and noinline attribute are both needed: the former is to avoid linking issue (duplicate symbol), + // while the second prevent too aggressive optimizations in fast-math mode: + #define EIGEN_TMP_NOOPT_ATTRIB EIGEN_DEVICE_FUNC inline __attribute__((noinline,optimize("no-finite-math-only"))) +#endif + +template<> EIGEN_TMP_NOOPT_ATTRIB bool isnan_impl(const long double& x) { return __builtin_isnan(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isnan_impl(const double& x) { return __builtin_isnan(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isnan_impl(const float& x) { return __builtin_isnan(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isinf_impl(const double& x) { return __builtin_isinf(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isinf_impl(const float& x) { return __builtin_isinf(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isinf_impl(const long double& x) { return __builtin_isinf(x); } + +#undef EIGEN_TMP_NOOPT_ATTRIB + +#endif + +#endif + +// The following overload are defined at the end of this file +template EIGEN_DEVICE_FUNC bool isfinite_impl(const std::complex& x); +template EIGEN_DEVICE_FUNC bool isnan_impl(const std::complex& x); +template EIGEN_DEVICE_FUNC bool isinf_impl(const std::complex& x); + +template T generic_fast_tanh_float(const T& a_x); + +} // end namespace internal + +/**************************************************************************** +* Generic math functions * +****************************************************************************/ + +namespace numext { + +#ifndef __CUDA_ARCH__ +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T mini(const T& x, const T& y) +{ + EIGEN_USING_STD_MATH(min); + return min EIGEN_NOT_A_MACRO (x,y); +} + +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T maxi(const T& x, const T& y) +{ + EIGEN_USING_STD_MATH(max); + return max EIGEN_NOT_A_MACRO (x,y); +} +#else +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T mini(const T& x, const T& y) +{ + return y < x ? y : x; +} +template<> +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE float mini(const float& x, const float& y) +{ + return fminf(x, y); +} +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T maxi(const T& x, const T& y) +{ + return x < y ? y : x; +} +template<> +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE float maxi(const float& x, const float& y) +{ + return fmaxf(x, y); +} +#endif + + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(real, Scalar) real(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(real, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) >::type real_ref(const Scalar& x) +{ + return internal::real_ref_impl::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) real_ref(Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(real_ref, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(imag, Scalar) imag(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(imag, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(arg, Scalar) arg(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(arg, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) >::type imag_ref(const Scalar& x) +{ + return internal::imag_ref_impl::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) imag_ref(Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(imag_ref, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(conj, Scalar) conj(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(conj, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(abs2, Scalar) abs2(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(abs2, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(norm1, Scalar) norm1(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(norm1, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(hypot, Scalar) hypot(const Scalar& x, const Scalar& y) +{ + return EIGEN_MATHFUNC_IMPL(hypot, Scalar)::run(x, y); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(log1p, Scalar) log1p(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(log1p, Scalar)::run(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float log1p(const float &x) { return ::log1pf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double log1p(const double &x) { return ::log1p(x); } +#endif + +template +EIGEN_DEVICE_FUNC +inline typename internal::pow_impl::result_type pow(const ScalarX& x, const ScalarY& y) +{ + return internal::pow_impl::run(x, y); +} + +template EIGEN_DEVICE_FUNC bool (isnan) (const T &x) { return internal::isnan_impl(x); } +template EIGEN_DEVICE_FUNC bool (isinf) (const T &x) { return internal::isinf_impl(x); } +template EIGEN_DEVICE_FUNC bool (isfinite)(const T &x) { return internal::isfinite_impl(x); } + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(round, Scalar) round(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(round, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +T (floor)(const T& x) +{ + EIGEN_USING_STD_MATH(floor); + return floor(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float floor(const float &x) { return ::floorf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double floor(const double &x) { return ::floor(x); } +#endif + +template +EIGEN_DEVICE_FUNC +T (ceil)(const T& x) +{ + EIGEN_USING_STD_MATH(ceil); + return ceil(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float ceil(const float &x) { return ::ceilf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double ceil(const double &x) { return ::ceil(x); } +#endif + + +/** Log base 2 for 32 bits positive integers. + * Conveniently returns 0 for x==0. */ +inline int log2(int x) +{ + eigen_assert(x>=0); + unsigned int v(x); + static const int table[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return table[(v * 0x07C4ACDDU) >> 27]; +} + +/** \returns the square root of \a x. + * + * It is essentially equivalent to \code using std::sqrt; return sqrt(x); \endcode, + * but slightly faster for float/double and some compilers (e.g., gcc), thanks to + * specializations when SSE is enabled. + * + * It's usage is justified in performance critical functions, like norm/normalize. + */ +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T sqrt(const T &x) +{ + EIGEN_USING_STD_MATH(sqrt); + return sqrt(x); +} + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T log(const T &x) { + EIGEN_USING_STD_MATH(log); + return log(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float log(const float &x) { return ::logf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double log(const double &x) { return ::log(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +typename internal::enable_if::IsSigned || NumTraits::IsComplex,typename NumTraits::Real>::type +abs(const T &x) { + EIGEN_USING_STD_MATH(abs); + return abs(x); +} + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +typename internal::enable_if::IsSigned || NumTraits::IsComplex),typename NumTraits::Real>::type +abs(const T &x) { + return x; +} + +#if defined(__SYCL_DEVICE_ONLY__) +EIGEN_ALWAYS_INLINE float abs(float x) { return cl::sycl::fabs(x); } +EIGEN_ALWAYS_INLINE double abs(double x) { return cl::sycl::fabs(x); } +#endif // defined(__SYCL_DEVICE_ONLY__) + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float abs(const float &x) { return ::fabsf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double abs(const double &x) { return ::fabs(x); } + +template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float abs(const std::complex& x) { + return ::hypotf(x.real(), x.imag()); +} + +template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double abs(const std::complex& x) { + return ::hypot(x.real(), x.imag()); +} +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T exp(const T &x) { + EIGEN_USING_STD_MATH(exp); + return exp(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float exp(const float &x) { return ::expf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double exp(const double &x) { return ::exp(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T cos(const T &x) { + EIGEN_USING_STD_MATH(cos); + return cos(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float cos(const float &x) { return ::cosf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double cos(const double &x) { return ::cos(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T sin(const T &x) { + EIGEN_USING_STD_MATH(sin); + return sin(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float sin(const float &x) { return ::sinf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double sin(const double &x) { return ::sin(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T tan(const T &x) { + EIGEN_USING_STD_MATH(tan); + return tan(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float tan(const float &x) { return ::tanf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double tan(const double &x) { return ::tan(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T acos(const T &x) { + EIGEN_USING_STD_MATH(acos); + return acos(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float acos(const float &x) { return ::acosf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double acos(const double &x) { return ::acos(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T asin(const T &x) { + EIGEN_USING_STD_MATH(asin); + return asin(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float asin(const float &x) { return ::asinf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double asin(const double &x) { return ::asin(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T atan(const T &x) { + EIGEN_USING_STD_MATH(atan); + return atan(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float atan(const float &x) { return ::atanf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double atan(const double &x) { return ::atan(x); } +#endif + + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T cosh(const T &x) { + EIGEN_USING_STD_MATH(cosh); + return cosh(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float cosh(const float &x) { return ::coshf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double cosh(const double &x) { return ::cosh(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T sinh(const T &x) { + EIGEN_USING_STD_MATH(sinh); + return sinh(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float sinh(const float &x) { return ::sinhf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double sinh(const double &x) { return ::sinh(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T tanh(const T &x) { + EIGEN_USING_STD_MATH(tanh); + return tanh(x); +} + +#if (!defined(__CUDACC__)) && EIGEN_FAST_MATH +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float tanh(float x) { return internal::generic_fast_tanh_float(x); } +#endif + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float tanh(const float &x) { return ::tanhf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double tanh(const double &x) { return ::tanh(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T fmod(const T& a, const T& b) { + EIGEN_USING_STD_MATH(fmod); + return fmod(a, b); +} + +#ifdef __CUDACC__ +template <> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float fmod(const float& a, const float& b) { + return ::fmodf(a, b); +} + +template <> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double fmod(const double& a, const double& b) { + return ::fmod(a, b); +} +#endif + +} // end namespace numext + +namespace internal { + +template +EIGEN_DEVICE_FUNC bool isfinite_impl(const std::complex& x) +{ + return (numext::isfinite)(numext::real(x)) && (numext::isfinite)(numext::imag(x)); +} + +template +EIGEN_DEVICE_FUNC bool isnan_impl(const std::complex& x) +{ + return (numext::isnan)(numext::real(x)) || (numext::isnan)(numext::imag(x)); +} + +template +EIGEN_DEVICE_FUNC bool isinf_impl(const std::complex& x) +{ + return ((numext::isinf)(numext::real(x)) || (numext::isinf)(numext::imag(x))) && (!(numext::isnan)(x)); +} + +/**************************************************************************** +* Implementation of fuzzy comparisons * +****************************************************************************/ + +template +struct scalar_fuzzy_default_impl {}; + +template +struct scalar_fuzzy_default_impl +{ + typedef typename NumTraits::Real RealScalar; + template EIGEN_DEVICE_FUNC + static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) + { + return numext::abs(x) <= numext::abs(y) * prec; + } + EIGEN_DEVICE_FUNC + static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) + { + return numext::abs(x - y) <= numext::mini(numext::abs(x), numext::abs(y)) * prec; + } + EIGEN_DEVICE_FUNC + static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar& prec) + { + return x <= y || isApprox(x, y, prec); + } +}; + +template +struct scalar_fuzzy_default_impl +{ + typedef typename NumTraits::Real RealScalar; + template EIGEN_DEVICE_FUNC + static inline bool isMuchSmallerThan(const Scalar& x, const Scalar&, const RealScalar&) + { + return x == Scalar(0); + } + EIGEN_DEVICE_FUNC + static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar&) + { + return x == y; + } + EIGEN_DEVICE_FUNC + static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar&) + { + return x <= y; + } +}; + +template +struct scalar_fuzzy_default_impl +{ + typedef typename NumTraits::Real RealScalar; + template EIGEN_DEVICE_FUNC + static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) + { + return numext::abs2(x) <= numext::abs2(y) * prec * prec; + } + EIGEN_DEVICE_FUNC + static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) + { + return numext::abs2(x - y) <= numext::mini(numext::abs2(x), numext::abs2(y)) * prec * prec; + } +}; + +template +struct scalar_fuzzy_impl : scalar_fuzzy_default_impl::IsComplex, NumTraits::IsInteger> {}; + +template EIGEN_DEVICE_FUNC +inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, + const typename NumTraits::Real &precision = NumTraits::dummy_precision()) +{ + return scalar_fuzzy_impl::template isMuchSmallerThan(x, y, precision); +} + +template EIGEN_DEVICE_FUNC +inline bool isApprox(const Scalar& x, const Scalar& y, + const typename NumTraits::Real &precision = NumTraits::dummy_precision()) +{ + return scalar_fuzzy_impl::isApprox(x, y, precision); +} + +template EIGEN_DEVICE_FUNC +inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, + const typename NumTraits::Real &precision = NumTraits::dummy_precision()) +{ + return scalar_fuzzy_impl::isApproxOrLessThan(x, y, precision); +} + +/****************************************** +*** The special case of the bool type *** +******************************************/ + +template<> struct random_impl +{ + static inline bool run() + { + return random(0,1)==0 ? false : true; + } +}; + +template<> struct scalar_fuzzy_impl +{ + typedef bool RealScalar; + + template EIGEN_DEVICE_FUNC + static inline bool isMuchSmallerThan(const bool& x, const bool&, const bool&) + { + return !x; + } + + EIGEN_DEVICE_FUNC + static inline bool isApprox(bool x, bool y, bool) + { + return x == y; + } + + EIGEN_DEVICE_FUNC + static inline bool isApproxOrLessThan(const bool& x, const bool& y, const bool&) + { + return (!x) || y; + } + +}; + + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_MATHFUNCTIONS_H diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/MathFunctionsImpl.h b/splinter/thirdparty/Eigen/Eigen/src/Core/MathFunctionsImpl.h new file mode 100644 index 0000000000..9c1ceb0eb0 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/MathFunctionsImpl.h @@ -0,0 +1,101 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Pedro Gonnet (pedro.gonnet@gmail.com) +// Copyright (C) 2016 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_MATHFUNCTIONSIMPL_H +#define EIGEN_MATHFUNCTIONSIMPL_H + +namespace Eigen { + +namespace internal { + +/** \internal \returns the hyperbolic tan of \a a (coeff-wise) + Doesn't do anything fancy, just a 13/6-degree rational interpolant which + is accurate up to a couple of ulp in the range [-9, 9], outside of which + the tanh(x) = +/-1. + + This implementation works on both scalars and packets. +*/ +template +T generic_fast_tanh_float(const T& a_x) +{ + // Clamp the inputs to the range [-9, 9] since anything outside + // this range is +/-1.0f in single-precision. + const T plus_9 = pset1(9.f); + const T minus_9 = pset1(-9.f); + // NOTE GCC prior to 6.3 might improperly optimize this max/min + // step such that if a_x is nan, x will be either 9 or -9, + // and tanh will return 1 or -1 instead of nan. + // This is supposed to be fixed in gcc6.3, + // see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72867 + const T x = pmax(minus_9,pmin(plus_9,a_x)); + // The monomial coefficients of the numerator polynomial (odd). + const T alpha_1 = pset1(4.89352455891786e-03f); + const T alpha_3 = pset1(6.37261928875436e-04f); + const T alpha_5 = pset1(1.48572235717979e-05f); + const T alpha_7 = pset1(5.12229709037114e-08f); + const T alpha_9 = pset1(-8.60467152213735e-11f); + const T alpha_11 = pset1(2.00018790482477e-13f); + const T alpha_13 = pset1(-2.76076847742355e-16f); + + // The monomial coefficients of the denominator polynomial (even). + const T beta_0 = pset1(4.89352518554385e-03f); + const T beta_2 = pset1(2.26843463243900e-03f); + const T beta_4 = pset1(1.18534705686654e-04f); + const T beta_6 = pset1(1.19825839466702e-06f); + + // Since the polynomials are odd/even, we need x^2. + const T x2 = pmul(x, x); + + // Evaluate the numerator polynomial p. + T p = pmadd(x2, alpha_13, alpha_11); + p = pmadd(x2, p, alpha_9); + p = pmadd(x2, p, alpha_7); + p = pmadd(x2, p, alpha_5); + p = pmadd(x2, p, alpha_3); + p = pmadd(x2, p, alpha_1); + p = pmul(x, p); + + // Evaluate the denominator polynomial p. + T q = pmadd(x2, beta_6, beta_4); + q = pmadd(x2, q, beta_2); + q = pmadd(x2, q, beta_0); + + // Divide the numerator by the denominator. + return pdiv(p, q); +} + +template +EIGEN_STRONG_INLINE +RealScalar positive_real_hypot(const RealScalar& x, const RealScalar& y) +{ + EIGEN_USING_STD_MATH(sqrt); + RealScalar p, qp; + p = numext::maxi(x,y); + if(p==RealScalar(0)) return RealScalar(0); + qp = numext::mini(y,x) / p; + return p * sqrt(RealScalar(1) + qp*qp); +} + +template +struct hypot_impl +{ + typedef typename NumTraits::Real RealScalar; + static inline RealScalar run(const Scalar& x, const Scalar& y) + { + EIGEN_USING_STD_MATH(abs); + return positive_real_hypot(abs(x), abs(y)); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_MATHFUNCTIONSIMPL_H diff --git a/splinter/src/Core/Matrix.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Matrix.h similarity index 71% rename from splinter/src/Core/Matrix.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/Matrix.h index 02be142d8c..90c336d8ca 100644 --- a/splinter/src/Core/Matrix.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Matrix.h @@ -13,6 +13,45 @@ namespace Eigen { +namespace internal { +template +struct traits > +{ +private: + enum { size = internal::size_at_compile_time<_Rows,_Cols>::ret }; + typedef typename find_best_packet<_Scalar,size>::type PacketScalar; + enum { + row_major_bit = _Options&RowMajor ? RowMajorBit : 0, + is_dynamic_size_storage = _MaxRows==Dynamic || _MaxCols==Dynamic, + max_size = is_dynamic_size_storage ? Dynamic : _MaxRows*_MaxCols, + default_alignment = compute_default_alignment<_Scalar,max_size>::value, + actual_alignment = ((_Options&DontAlign)==0) ? default_alignment : 0, + required_alignment = unpacket_traits::alignment, + packet_access_bit = (packet_traits<_Scalar>::Vectorizable && (EIGEN_UNALIGNED_VECTORIZE || (actual_alignment>=required_alignment))) ? PacketAccessBit : 0 + }; + +public: + typedef _Scalar Scalar; + typedef Dense StorageKind; + typedef Eigen::Index StorageIndex; + typedef MatrixXpr XprKind; + enum { + RowsAtCompileTime = _Rows, + ColsAtCompileTime = _Cols, + MaxRowsAtCompileTime = _MaxRows, + MaxColsAtCompileTime = _MaxCols, + Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret, + Options = _Options, + InnerStrideAtCompileTime = 1, + OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime, + + // FIXME, the following flag in only used to define NeedsToAlign in PlainObjectBase + EvaluatorFlags = LinearAccessBit | DirectAccessBit | packet_access_bit | row_major_bit, + Alignment = actual_alignment + }; +}; +} + /** \class Matrix * \ingroup Core_Module * @@ -24,13 +63,13 @@ namespace Eigen { * The %Matrix class encompasses \em both fixed-size and dynamic-size objects (\ref fixedsize "note"). * * The first three template parameters are required: - * \tparam _Scalar \anchor matrix_tparam_scalar Numeric type, e.g. float, double, int or std::complex. - * User defined sclar types are supported as well (see \ref user_defined_scalars "here"). + * \tparam _Scalar Numeric type, e.g. float, double, int or std::complex. + * User defined scalar types are supported as well (see \ref user_defined_scalars "here"). * \tparam _Rows Number of rows, or \b Dynamic * \tparam _Cols Number of columns, or \b Dynamic * * The remaining template parameters are optional -- in most cases you don't have to worry about them. - * \tparam _Options \anchor matrix_tparam_options A combination of either \b #RowMajor or \b #ColMajor, and of either + * \tparam _Options A combination of either \b #RowMajor or \b #ColMajor, and of either * \b #AutoAlign or \b #DontAlign. * The former controls \ref TopicStorageOrders "storage order", and defaults to column-major. The latter controls alignment, which is required * for vectorization. It defaults to aligning matrices except for fixed sizes that aren't a multiple of the packet size. @@ -67,7 +106,7 @@ namespace Eigen { * \endcode * * 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_MATRIX_PLUGIN. + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_MATRIX_PLUGIN. * * Some notes: * @@ -97,32 +136,44 @@ namespace Eigen { * are the dimensions of the original matrix, while _Rows and _Cols are Dynamic. * * - * \see MatrixBase for the majority of the API methods for matrices, \ref TopicClassHierarchy, - * \ref TopicStorageOrders + * ABI and storage layout + * + * The table below summarizes the ABI of some possible Matrix instances which is fixed thorough the lifetime of Eigen 3. + * + * + * + * + * + * + *
Matrix typeEquivalent C structure
\code Matrix \endcode\code + * struct { + * T *data; // with (size_t(data)%EIGEN_MAX_ALIGN_BYTES)==0 + * Eigen::Index rows, cols; + * }; + * \endcode
\code + * Matrix + * Matrix \endcode\code + * struct { + * T *data; // with (size_t(data)%EIGEN_MAX_ALIGN_BYTES)==0 + * Eigen::Index size; + * }; + * \endcode
\code Matrix \endcode\code + * struct { + * T data[Rows*Cols]; // with (size_t(data)%A(Rows*Cols*sizeof(T)))==0 + * }; + * \endcode
\code Matrix \endcode\code + * struct { + * T data[MaxRows*MaxCols]; // with (size_t(data)%A(MaxRows*MaxCols*sizeof(T)))==0 + * Eigen::Index rows, cols; + * }; + * \endcode
+ * Note that in this table Rows, Cols, MaxRows and MaxCols are all positive integers. A(S) is defined to the largest possible power-of-two + * smaller to EIGEN_MAX_STATIC_ALIGN_BYTES. + * + * \see MatrixBase for the majority of the API methods for matrices, \ref TopicClassHierarchy, + * \ref TopicStorageOrders */ -namespace internal { -template -struct traits > -{ - typedef _Scalar Scalar; - typedef Dense StorageKind; - typedef DenseIndex Index; - typedef MatrixXpr XprKind; - enum { - RowsAtCompileTime = _Rows, - ColsAtCompileTime = _Cols, - MaxRowsAtCompileTime = _MaxRows, - MaxColsAtCompileTime = _MaxCols, - Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret, - CoeffReadCost = NumTraits::ReadCost, - Options = _Options, - InnerStrideAtCompileTime = 1, - OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime - }; -}; -} - template class Matrix : public PlainObjectBase > @@ -151,6 +202,7 @@ class Matrix * * \callgraph */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix& operator=(const Matrix& other) { return Base::_set(other); @@ -167,7 +219,8 @@ class Matrix * remain row-vectors and vectors remain vectors. */ template - EIGEN_STRONG_INLINE Matrix& operator=(const MatrixBase& other) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Matrix& operator=(const DenseBase& other) { return Base::_set(other); } @@ -179,12 +232,14 @@ class Matrix * \copydetails DenseBase::operator=(const EigenBase &other) */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix& operator=(const EigenBase &other) { return Base::operator=(other); } template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix& operator=(const ReturnByValue& func) { return Base::operator=(func); @@ -200,6 +255,7 @@ class Matrix * * \sa resize(Index,Index) */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix() : Base() { Base::_check_template_params(); @@ -207,60 +263,87 @@ class Matrix } // FIXME is it still needed - Matrix(internal::constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC + explicit Matrix(internal::constructor_without_unaligned_array_assert) : Base(internal::constructor_without_unaligned_array_assert()) { Base::_check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - Matrix(Matrix&& other) +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + Matrix(Matrix&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_constructible::value) : Base(std::move(other)) { Base::_check_template_params(); if (RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic) Base::_set_noalias(other); } - Matrix& operator=(Matrix&& other) + EIGEN_DEVICE_FUNC + Matrix& operator=(Matrix&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_assignable::value) { other.swap(*this); return *this; } #endif - /** \brief Constructs a vector or row-vector with given dimension. \only_for_vectors - * - * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, - * it is redundant to pass the dimension here, so it makes more sense to use the default - * constructor Matrix() instead. - */ - EIGEN_STRONG_INLINE explicit Matrix(Index dim) - : Base(dim, RowsAtCompileTime == 1 ? 1 : dim, ColsAtCompileTime == 1 ? 1 : dim) + #ifndef EIGEN_PARSED_BY_DOXYGEN + + // This constructor is for both 1x1 matrices and dynamic vectors + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE explicit Matrix(const T& x) { Base::_check_template_params(); - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Matrix) - eigen_assert(dim >= 0); - eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == dim); - EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + Base::template _init1(x); } - #ifndef EIGEN_PARSED_BY_DOXYGEN template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const T0& x, const T1& y) { Base::_check_template_params(); Base::template _init2(x, y); } #else + /** \brief Constructs a fixed-sized matrix initialized with coefficients starting at \a data */ + EIGEN_DEVICE_FUNC + explicit Matrix(const Scalar *data); + + /** \brief Constructs a vector or row-vector with given dimension. \only_for_vectors + * + * This is useful for dynamic-size vectors. For fixed-size vectors, + * it is redundant to pass these parameters, so one should use the default constructor + * Matrix() instead. + * + * \warning This constructor is disabled for fixed-size \c 1x1 matrices. For instance, + * calling Matrix(1) will call the initialization constructor: Matrix(const Scalar&). + * For fixed-size \c 1x1 matrices it is therefore recommended to use the default + * constructor Matrix() instead, especially when using one of the non standard + * \c EIGEN_INITIALIZE_MATRICES_BY_{ZERO,\c NAN} macros (see \ref TopicPreprocessorDirectives). + */ + EIGEN_STRONG_INLINE explicit Matrix(Index dim); + /** \brief Constructs an initialized 1x1 matrix with the given coefficient */ + Matrix(const Scalar& x); /** \brief Constructs an uninitialized matrix with \a rows rows and \a cols columns. * * This is useful for dynamic-size matrices. For fixed-size matrices, * it is redundant to pass these parameters, so one should use the default constructor - * Matrix() instead. */ + * Matrix() instead. + * + * \warning This constructor is disabled for fixed-size \c 1x2 and \c 2x1 vectors. For instance, + * calling Matrix2f(2,1) will call the initialization constructor: Matrix(const Scalar& x, const Scalar& y). + * For fixed-size \c 1x2 or \c 2x1 vectors it is therefore recommended to use the default + * constructor Matrix() instead, especially when using one of the non standard + * \c EIGEN_INITIALIZE_MATRICES_BY_{ZERO,\c NAN} macros (see \ref TopicPreprocessorDirectives). + */ + EIGEN_DEVICE_FUNC Matrix(Index rows, Index cols); + /** \brief Constructs an initialized 2D vector with given coefficients */ Matrix(const Scalar& x, const Scalar& y); #endif /** \brief Constructs an initialized 3D vector with given coefficients */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z) { Base::_check_template_params(); @@ -270,6 +353,7 @@ class Matrix m_storage.data()[2] = z; } /** \brief Constructs an initialized 4D vector with given coefficients */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z, const Scalar& w) { Base::_check_template_params(); @@ -280,76 +364,33 @@ class Matrix m_storage.data()[3] = w; } - explicit Matrix(const Scalar *data); - /** \brief Constructor copying the value of the expression \a other */ - template - EIGEN_STRONG_INLINE Matrix(const MatrixBase& other) - : Base(other.rows() * other.cols(), other.rows(), other.cols()) - { - // This test resides here, to bring the error messages closer to the user. Normally, these checks - // are performed deeply within the library, thus causing long and scary error traces. - 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::_check_template_params(); - Base::_set_noalias(other); - } /** \brief Copy constructor */ - EIGEN_STRONG_INLINE Matrix(const Matrix& other) - : Base(other.rows() * other.cols(), other.rows(), other.cols()) - { - Base::_check_template_params(); - Base::_set_noalias(other); - } - /** \brief Copy constructor with in-place evaluation */ - template - EIGEN_STRONG_INLINE Matrix(const ReturnByValue& other) - { - Base::_check_template_params(); - Base::resize(other.rows(), other.cols()); - other.evalTo(*this); - } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Matrix(const Matrix& other) : Base(other) + { } /** \brief Copy constructor for generic expressions. * \sa MatrixBase::operator=(const EigenBase&) */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const EigenBase &other) - : Base(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) - { - Base::_check_template_params(); - Base::_resize_to_match(other); - // FIXME/CHECK: isn't *this = other.derived() more efficient. it allows to - // go for pure _set() implementations, right? - *this = other; - } - - /** \internal - * \brief Override MatrixBase::swap() since for dynamic-sized matrices - * of same type it is enough to swap the data pointers. - */ - template - void swap(MatrixBase const & other) - { this->_swap(other.derived()); } + : Base(other.derived()) + { } - inline Index innerStride() const { return 1; } - inline Index outerStride() const { return this->innerSize(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return 1; } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return this->innerSize(); } /////////// Geometry module /////////// template + EIGEN_DEVICE_FUNC explicit Matrix(const RotationBase& r); template + EIGEN_DEVICE_FUNC Matrix& operator=(const RotationBase& r); - #ifdef EIGEN2_SUPPORT - template - explicit Matrix(const eigen2_RotationBase& r); - template - Matrix& operator=(const eigen2_RotationBase& r); - #endif - // allow to extend Matrix outside Eigen #ifdef EIGEN_MATRIX_PLUGIN #include EIGEN_MATRIX_PLUGIN diff --git a/splinter/src/Core/MatrixBase.h b/splinter/thirdparty/Eigen/Eigen/src/Core/MatrixBase.h similarity index 64% rename from splinter/src/Core/MatrixBase.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/MatrixBase.h index e83ef4dc05..05db488131 100644 --- a/splinter/src/Core/MatrixBase.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/MatrixBase.h @@ -41,9 +41,9 @@ namespace Eigen { * \endcode * * 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_MATRIXBASE_PLUGIN. + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_MATRIXBASE_PLUGIN. * - * \sa \ref TopicClassHierarchy + * \sa \blank \ref TopicClassHierarchy */ template class MatrixBase : public DenseBase @@ -52,7 +52,7 @@ template class MatrixBase #ifndef EIGEN_PARSED_BY_DOXYGEN typedef MatrixBase StorageBaseType; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; + typedef typename internal::traits::StorageIndex StorageIndex; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; @@ -66,7 +66,6 @@ template class MatrixBase using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; - using Base::CoeffReadCost; using Base::derived; using Base::const_cast_derived; @@ -98,25 +97,14 @@ template class MatrixBase /** \returns the size of the main diagonal, which is min(rows(),cols()). * \sa rows(), cols(), SizeAtCompileTime. */ - inline Index diagonalSize() const { return (std::min)(rows(),cols()); } + EIGEN_DEVICE_FUNC + inline Index diagonalSize() const { return (numext::mini)(rows(),cols()); } - /** \brief The plain matrix type corresponding to this expression. - * - * This is not necessarily exactly the return type of eval(). In the case of plain matrices, - * the return type of eval() is a const reference to a matrix, not a matrix! It is however guaranteed - * that the return type of eval() is either PlainObject or const PlainObject&. - */ - typedef Matrix::Scalar, - internal::traits::RowsAtCompileTime, - internal::traits::ColsAtCompileTime, - AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), - internal::traits::MaxRowsAtCompileTime, - internal::traits::MaxColsAtCompileTime - > PlainObject; + typedef typename Base::PlainObject PlainObject; #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal Represents a matrix with all coefficients equal to one another*/ - typedef CwiseNullaryOp,Derived> ConstantReturnType; + typedef CwiseNullaryOp,PlainObject> ConstantReturnType; /** \internal the return type of MatrixBase::adjoint() */ typedef typename internal::conditional::IsComplex, CwiseUnaryOp, ConstTransposeReturnType>, @@ -125,7 +113,7 @@ template class MatrixBase /** \internal Return type of eigenvalues() */ typedef Matrix, internal::traits::ColsAtCompileTime, 1, ColMajor> EigenvaluesReturnType; /** \internal the return type of identity */ - typedef CwiseNullaryOp,Derived> IdentityReturnType; + typedef CwiseNullaryOp,PlainObject> IdentityReturnType; /** \internal the return type of unit vectors */ typedef Block, SquareMatrixType>, internal::traits::RowsAtCompileTime, @@ -133,6 +121,7 @@ template class MatrixBase #endif // not EIGEN_PARSED_BY_DOXYGEN #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::MatrixBase +#define EIGEN_DOC_UNARY_ADDONS(X,Y) # include "../plugins/CommonCwiseUnaryOps.h" # include "../plugins/CommonCwiseBinaryOps.h" # include "../plugins/MatrixCwiseUnaryOps.h" @@ -141,41 +130,44 @@ template class MatrixBase # include EIGEN_MATRIXBASE_PLUGIN # endif #undef EIGEN_CURRENT_STORAGE_BASE_CLASS +#undef EIGEN_DOC_UNARY_ADDONS /** Special case of the template operator=, in order to prevent the compiler * from generating a default operator= (issue hit with g++ 4.1) */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const MatrixBase& other); // We cannot inherit here via Base::operator= since it is causing // trouble with MSVC. template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const DenseBase& other); template + EIGEN_DEVICE_FUNC Derived& operator=(const EigenBase& other); template + EIGEN_DEVICE_FUNC Derived& operator=(const ReturnByValue& other); - template - Derived& lazyAssign(const ProductBase& other); - - template - Derived& lazyAssign(const MatrixPowerProduct& other); - template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator+=(const MatrixBase& other); template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator-=(const MatrixBase& other); template - const typename ProductReturnType::Type + EIGEN_DEVICE_FUNC + const Product operator*(const MatrixBase &other) const; template - const typename LazyProductReturnType::Type + EIGEN_DEVICE_FUNC + const Product lazyProduct(const MatrixBase &other) const; template @@ -188,84 +180,93 @@ template class MatrixBase void applyOnTheRight(const EigenBase& other); template - const DiagonalProduct + EIGEN_DEVICE_FUNC + const Product operator*(const DiagonalBase &diagonal) const; template - typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType + EIGEN_DEVICE_FUNC + typename ScalarBinaryOpTraits::Scalar,typename internal::traits::Scalar>::ReturnType dot(const MatrixBase& other) const; - #ifdef EIGEN2_SUPPORT - template - Scalar eigen2_dot(const MatrixBase& other) const; - #endif - - RealScalar squaredNorm() const; - RealScalar norm() const; + EIGEN_DEVICE_FUNC RealScalar squaredNorm() const; + EIGEN_DEVICE_FUNC RealScalar norm() const; RealScalar stableNorm() const; RealScalar blueNorm() const; RealScalar hypotNorm() const; - const PlainObject normalized() const; - void normalize(); + EIGEN_DEVICE_FUNC const PlainObject normalized() const; + EIGEN_DEVICE_FUNC const PlainObject stableNormalized() const; + EIGEN_DEVICE_FUNC void normalize(); + EIGEN_DEVICE_FUNC void stableNormalize(); - const AdjointReturnType adjoint() const; - void adjointInPlace(); + EIGEN_DEVICE_FUNC const AdjointReturnType adjoint() const; + EIGEN_DEVICE_FUNC void adjointInPlace(); typedef Diagonal DiagonalReturnType; + EIGEN_DEVICE_FUNC DiagonalReturnType diagonal(); + typedef typename internal::add_const >::type ConstDiagonalReturnType; + EIGEN_DEVICE_FUNC ConstDiagonalReturnType diagonal() const; template struct DiagonalIndexReturnType { typedef Diagonal Type; }; template struct ConstDiagonalIndexReturnType { typedef const Diagonal Type; }; - template typename DiagonalIndexReturnType::Type diagonal(); - template typename ConstDiagonalIndexReturnType::Type diagonal() const; - + template + EIGEN_DEVICE_FUNC + typename DiagonalIndexReturnType::Type diagonal(); + + template + EIGEN_DEVICE_FUNC + typename ConstDiagonalIndexReturnType::Type diagonal() const; + typedef Diagonal DiagonalDynamicIndexReturnType; typedef typename internal::add_const >::type ConstDiagonalDynamicIndexReturnType; + EIGEN_DEVICE_FUNC DiagonalDynamicIndexReturnType diagonal(Index index); + EIGEN_DEVICE_FUNC ConstDiagonalDynamicIndexReturnType diagonal(Index index) const; - #ifdef EIGEN2_SUPPORT - template typename internal::eigen2_part_return_type::type part(); - template const typename internal::eigen2_part_return_type::type part() const; - - // 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. - template class U> - const DiagonalWrapper part() const - { return diagonal().asDiagonal(); } - #endif // EIGEN2_SUPPORT - template struct TriangularViewReturnType { typedef TriangularView Type; }; template struct ConstTriangularViewReturnType { typedef const TriangularView Type; }; - template typename TriangularViewReturnType::Type triangularView(); - template typename ConstTriangularViewReturnType::Type triangularView() const; + template + EIGEN_DEVICE_FUNC + typename TriangularViewReturnType::Type triangularView(); + template + EIGEN_DEVICE_FUNC + typename ConstTriangularViewReturnType::Type triangularView() const; template struct SelfAdjointViewReturnType { typedef SelfAdjointView Type; }; template struct ConstSelfAdjointViewReturnType { typedef const SelfAdjointView Type; }; - template typename SelfAdjointViewReturnType::Type selfadjointView(); - template typename ConstSelfAdjointViewReturnType::Type selfadjointView() const; + template + EIGEN_DEVICE_FUNC + typename SelfAdjointViewReturnType::Type selfadjointView(); + template + EIGEN_DEVICE_FUNC + typename ConstSelfAdjointViewReturnType::Type selfadjointView() const; const SparseView sparseView(const Scalar& m_reference = Scalar(0), const typename NumTraits::Real& m_epsilon = NumTraits::dummy_precision()) const; - static const IdentityReturnType Identity(); - static const IdentityReturnType Identity(Index rows, Index cols); - static const BasisReturnType Unit(Index size, Index i); - static const BasisReturnType Unit(Index i); - static const BasisReturnType UnitX(); - static const BasisReturnType UnitY(); - static const BasisReturnType UnitZ(); - static const BasisReturnType UnitW(); - + EIGEN_DEVICE_FUNC static const IdentityReturnType Identity(); + EIGEN_DEVICE_FUNC static const IdentityReturnType Identity(Index rows, Index cols); + EIGEN_DEVICE_FUNC static const BasisReturnType Unit(Index size, Index i); + EIGEN_DEVICE_FUNC static const BasisReturnType Unit(Index i); + EIGEN_DEVICE_FUNC static const BasisReturnType UnitX(); + EIGEN_DEVICE_FUNC static const BasisReturnType UnitY(); + EIGEN_DEVICE_FUNC static const BasisReturnType UnitZ(); + EIGEN_DEVICE_FUNC static const BasisReturnType UnitW(); + + EIGEN_DEVICE_FUNC const DiagonalWrapper asDiagonal() const; const PermutationWrapper asPermutation() const; + EIGEN_DEVICE_FUNC Derived& setIdentity(); + EIGEN_DEVICE_FUNC Derived& setIdentity(Index rows, Index cols); bool isIdentity(const RealScalar& prec = NumTraits::dummy_precision()) const; @@ -284,7 +285,7 @@ template class MatrixBase * fuzzy comparison such as isApprox() * \sa isApprox(), operator!= */ template - inline bool operator==(const MatrixBase& other) const + EIGEN_DEVICE_FUNC inline bool operator==(const MatrixBase& other) const { return cwiseEqual(other).all(); } /** \returns true if at least one pair of coefficients of \c *this and \a other are not exactly equal to each other. @@ -292,64 +293,50 @@ template class MatrixBase * fuzzy comparison such as isApprox() * \sa isApprox(), operator== */ template - inline bool operator!=(const MatrixBase& other) const + EIGEN_DEVICE_FUNC inline bool operator!=(const MatrixBase& other) const { return cwiseNotEqual(other).any(); } NoAlias noalias(); - inline const ForceAlignedAccess forceAlignedAccess() const; - inline ForceAlignedAccess forceAlignedAccess(); - template inline typename internal::add_const_on_value_type,Derived&>::type>::type forceAlignedAccessIf() const; - template inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); - - Scalar trace() const; + // TODO forceAlignedAccess is temporarily disabled + // Need to find a nicer workaround. + inline const Derived& forceAlignedAccess() const { return derived(); } + inline Derived& forceAlignedAccess() { return derived(); } + template inline const Derived& forceAlignedAccessIf() const { return derived(); } + template inline Derived& forceAlignedAccessIf() { return derived(); } -/////////// Array module /////////// + EIGEN_DEVICE_FUNC Scalar trace() const; - template RealScalar lpNorm() const; + template EIGEN_DEVICE_FUNC RealScalar lpNorm() const; - MatrixBase& matrix() { return *this; } - const MatrixBase& matrix() const { return *this; } + EIGEN_DEVICE_FUNC MatrixBase& matrix() { return *this; } + EIGEN_DEVICE_FUNC const MatrixBase& matrix() const { return *this; } /** \returns an \link Eigen::ArrayBase Array \endlink expression of this matrix * \sa ArrayBase::matrix() */ - ArrayWrapper array() { return derived(); } - const ArrayWrapper array() const { return derived(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ArrayWrapper array() { return ArrayWrapper(derived()); } + /** \returns a const \link Eigen::ArrayBase Array \endlink expression of this matrix + * \sa ArrayBase::matrix() */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const ArrayWrapper array() const { return ArrayWrapper(derived()); } /////////// LU module /////////// - const FullPivLU fullPivLu() const; - const PartialPivLU partialPivLu() const; + inline const FullPivLU fullPivLu() const; + inline const PartialPivLU partialPivLu() const; - #if EIGEN2_SUPPORT_STAGE < STAGE20_RESOLVE_API_CONFLICTS - const LU lu() const; - #endif + inline const PartialPivLU lu() const; - #ifdef EIGEN2_SUPPORT - const LU eigen2_lu() const; - #endif + inline const Inverse inverse() const; - #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS - const PartialPivLU lu() const; - #endif - - #ifdef EIGEN2_SUPPORT template - void computeInverse(MatrixBase *result) const { - *result = this->inverse(); - } - #endif - - const internal::inverse_impl inverse() const; - template - void computeInverseAndDetWithCheck( + inline void computeInverseAndDetWithCheck( ResultType& inverse, typename ResultType::Scalar& determinant, bool& invertible, const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() ) const; template - void computeInverseWithCheck( + inline void computeInverseWithCheck( ResultType& inverse, bool& invertible, const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() @@ -358,65 +345,70 @@ template class MatrixBase /////////// Cholesky module /////////// - const LLT llt() const; - const LDLT ldlt() const; + inline const LLT llt() const; + inline const LDLT ldlt() const; /////////// QR module /////////// - const HouseholderQR householderQr() const; - const ColPivHouseholderQR colPivHouseholderQr() const; - const FullPivHouseholderQR fullPivHouseholderQr() const; - - #ifdef EIGEN2_SUPPORT - const QR qr() const; - #endif + inline const HouseholderQR householderQr() const; + inline const ColPivHouseholderQR colPivHouseholderQr() const; + inline const FullPivHouseholderQR fullPivHouseholderQr() const; + inline const CompleteOrthogonalDecomposition completeOrthogonalDecomposition() const; - EigenvaluesReturnType eigenvalues() const; - RealScalar operatorNorm() const; +/////////// Eigenvalues module /////////// -/////////// SVD module /////////// + inline EigenvaluesReturnType eigenvalues() const; + inline RealScalar operatorNorm() const; - JacobiSVD jacobiSvd(unsigned int computationOptions = 0) const; +/////////// SVD module /////////// - #ifdef EIGEN2_SUPPORT - SVD svd() const; - #endif + inline JacobiSVD jacobiSvd(unsigned int computationOptions = 0) const; + inline BDCSVD bdcSvd(unsigned int computationOptions = 0) const; /////////// Geometry module /////////// #ifndef EIGEN_PARSED_BY_DOXYGEN /// \internal helper struct to form the return type of the cross product template struct cross_product_return_type { - typedef typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType Scalar; + typedef typename ScalarBinaryOpTraits::Scalar,typename internal::traits::Scalar>::ReturnType Scalar; typedef Matrix type; }; #endif // EIGEN_PARSED_BY_DOXYGEN template - typename cross_product_return_type::type + EIGEN_DEVICE_FUNC +#ifndef EIGEN_PARSED_BY_DOXYGEN + inline typename cross_product_return_type::type +#else + inline PlainObject +#endif cross(const MatrixBase& other) const; + template - PlainObject cross3(const MatrixBase& other) const; - PlainObject unitOrthogonal(void) const; - Matrix eulerAngles(Index a0, Index a1, Index a2) const; - - #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS - ScalarMultipleReturnType operator*(const UniformScaling& s) const; + EIGEN_DEVICE_FUNC + inline PlainObject cross3(const MatrixBase& other) const; + + EIGEN_DEVICE_FUNC + inline PlainObject unitOrthogonal(void) const; + + EIGEN_DEVICE_FUNC + inline Matrix eulerAngles(Index a0, Index a1, Index a2) const; + // put this as separate enum value to work around possible GCC 4.3 bug (?) - enum { HomogeneousReturnTypeDirection = ColsAtCompileTime==1?Vertical:Horizontal }; + enum { HomogeneousReturnTypeDirection = ColsAtCompileTime==1&&RowsAtCompileTime==1 ? ((internal::traits::Flags&RowMajorBit)==RowMajorBit ? Horizontal : Vertical) + : ColsAtCompileTime==1 ? Vertical : Horizontal }; typedef Homogeneous HomogeneousReturnType; - HomogeneousReturnType homogeneous() const; - #endif - + EIGEN_DEVICE_FUNC + inline HomogeneousReturnType homogeneous() const; + enum { SizeMinusOne = SizeAtCompileTime==Dynamic ? Dynamic : SizeAtCompileTime-1 }; typedef Block::ColsAtCompileTime==1 ? SizeMinusOne : 1, internal::traits::ColsAtCompileTime==1 ? 1 : SizeMinusOne> ConstStartMinusOne; - typedef CwiseUnaryOp::Scalar>, - const ConstStartMinusOne > HNormalizedReturnType; - - const HNormalizedReturnType hnormalized() const; + typedef EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(ConstStartMinusOne,Scalar,quotient) HNormalizedReturnType; + EIGEN_DEVICE_FUNC + inline const HNormalizedReturnType hnormalized() const; ////////// Householder module /////////// @@ -461,49 +453,15 @@ template class MatrixBase const MatrixSquareRootReturnValue sqrt() const; const MatrixLogarithmReturnValue log() const; const MatrixPowerReturnValue pow(const RealScalar& p) const; - -#ifdef EIGEN2_SUPPORT - template - Derived& operator+=(const Flagged, 0, - EvalBeforeAssigningBit>& other); - - template - Derived& operator-=(const Flagged, 0, - EvalBeforeAssigningBit>& other); - - /** \deprecated because .lazy() is deprecated - * Overloaded for cache friendly product evaluation */ - template - Derived& lazyAssign(const Flagged& other) - { return lazyAssign(other._expression()); } - - template - const Flagged marked() const; - const Flagged lazy() const; - - inline const Cwise cwise() const; - inline Cwise cwise(); - - VectorBlock start(Index size); - const VectorBlock start(Index size) const; - VectorBlock end(Index size); - const VectorBlock end(Index size) const; - template VectorBlock start(); - template const VectorBlock start() const; - template VectorBlock end(); - template const VectorBlock end() const; - - Minor minor(Index row, Index col); - const Minor minor(Index row, Index col) const; -#endif + const MatrixComplexPowerReturnValue pow(const std::complex& p) const; protected: - MatrixBase() : Base() {} + EIGEN_DEVICE_FUNC MatrixBase() : Base() {} private: - explicit MatrixBase(int); - MatrixBase(int,int); - template explicit MatrixBase(const MatrixBase&); + EIGEN_DEVICE_FUNC explicit MatrixBase(int); + EIGEN_DEVICE_FUNC MatrixBase(int,int); + template EIGEN_DEVICE_FUNC explicit MatrixBase(const MatrixBase&); protected: // mixing arrays and matrices is not legal template Derived& operator+=(const ArrayBase& ) diff --git a/splinter/src/Core/NestByValue.h b/splinter/thirdparty/Eigen/Eigen/src/Core/NestByValue.h similarity index 72% rename from splinter/src/Core/NestByValue.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/NestByValue.h index a893b1761b..13adf070e8 100644 --- a/splinter/src/Core/NestByValue.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/NestByValue.h @@ -13,25 +13,24 @@ namespace Eigen { +namespace internal { +template +struct traits > : public traits +{}; +} + /** \class NestByValue * \ingroup Core_Module * * \brief Expression which must be nested by value * - * \param ExpressionType the type of the object of which we are requiring nesting-by-value + * \tparam ExpressionType the type of the object of which we are requiring nesting-by-value * * This class is the return type of MatrixBase::nestByValue() * and most of the time this is the only way it is used. * * \sa MatrixBase::nestByValue() */ - -namespace internal { -template -struct traits > : public traits -{}; -} - template class NestByValue : public internal::dense_xpr_base< NestByValue >::type { @@ -40,29 +39,29 @@ template class NestByValue typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(NestByValue) - inline NestByValue(const ExpressionType& matrix) : m_expression(matrix) {} + EIGEN_DEVICE_FUNC explicit inline NestByValue(const ExpressionType& matrix) : m_expression(matrix) {} - inline Index rows() const { return m_expression.rows(); } - inline Index cols() const { return m_expression.cols(); } - inline Index outerStride() const { return m_expression.outerStride(); } - inline Index innerStride() const { return m_expression.innerStride(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } - inline const CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index row, Index col) const { return m_expression.coeff(row, col); } - inline Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { return m_expression.const_cast_derived().coeffRef(row, col); } - inline const CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } - inline Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) { return m_expression.const_cast_derived().coeffRef(index); } @@ -91,7 +90,7 @@ template class NestByValue m_expression.const_cast_derived().template writePacket(index, x); } - operator const ExpressionType&() const { return m_expression; } + EIGEN_DEVICE_FUNC operator const ExpressionType&() const { return m_expression; } protected: const ExpressionType m_expression; diff --git a/splinter/src/Core/NoAlias.h b/splinter/thirdparty/Eigen/Eigen/src/Core/NoAlias.h similarity index 52% rename from splinter/src/Core/NoAlias.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/NoAlias.h index 768bfb18ca..33908010b4 100644 --- a/splinter/src/Core/NoAlias.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/NoAlias.h @@ -17,7 +17,7 @@ namespace Eigen { * * \brief Pseudo expression providing an operator = assuming no aliasing * - * \param ExpressionType the type of the object on which to do the lazy assignment + * \tparam ExpressionType the type of the object on which to do the lazy assignment * * This class represents an expression with special assignment operators * assuming no aliasing between the target expression and the source expression. @@ -30,62 +30,36 @@ namespace Eigen { template class StorageBase> class NoAlias { - typedef typename ExpressionType::Scalar Scalar; public: - NoAlias(ExpressionType& expression) : m_expression(expression) {} - - /** Behaves like MatrixBase::lazyAssign(other) - * \sa MatrixBase::lazyAssign() */ + typedef typename ExpressionType::Scalar Scalar; + + explicit NoAlias(ExpressionType& expression) : m_expression(expression) {} + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase& other) - { return internal::assign_selector::run(m_expression,other.derived()); } - - /** \sa MatrixBase::operator+= */ + { + call_assignment_no_alias(m_expression, other.derived(), internal::assign_op()); + return m_expression; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator+=(const StorageBase& other) { - typedef SelfCwiseBinaryOp, ExpressionType, OtherDerived> SelfAdder; - SelfAdder tmp(m_expression); - typedef typename internal::nested::type OtherDerivedNested; - typedef typename internal::remove_all::type _OtherDerivedNested; - internal::assign_selector::run(tmp,OtherDerivedNested(other.derived())); + call_assignment_no_alias(m_expression, other.derived(), internal::add_assign_op()); return m_expression; } - - /** \sa MatrixBase::operator-= */ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator-=(const StorageBase& other) { - typedef SelfCwiseBinaryOp, ExpressionType, OtherDerived> SelfAdder; - SelfAdder tmp(m_expression); - typedef typename internal::nested::type OtherDerivedNested; - typedef typename internal::remove_all::type _OtherDerivedNested; - internal::assign_selector::run(tmp,OtherDerivedNested(other.derived())); + call_assignment_no_alias(m_expression, other.derived(), internal::sub_assign_op()); return m_expression; } -#ifndef EIGEN_PARSED_BY_DOXYGEN - template - EIGEN_STRONG_INLINE ExpressionType& operator+=(const ProductBase& other) - { other.derived().addTo(m_expression); return m_expression; } - - template - EIGEN_STRONG_INLINE ExpressionType& operator-=(const ProductBase& other) - { other.derived().subTo(m_expression); return m_expression; } - - template - EIGEN_STRONG_INLINE ExpressionType& operator+=(const CoeffBasedProduct& other) - { return m_expression.derived() += CoeffBasedProduct(other.lhs(), other.rhs()); } - - template - EIGEN_STRONG_INLINE ExpressionType& operator-=(const CoeffBasedProduct& other) - { return m_expression.derived() -= CoeffBasedProduct(other.lhs(), other.rhs()); } - - template - ExpressionType& operator=(const ReturnByValue& func) - { return m_expression = func; } -#endif - + EIGEN_DEVICE_FUNC ExpressionType& expression() const { return m_expression; @@ -126,7 +100,7 @@ class NoAlias template NoAlias MatrixBase::noalias() { - return derived(); + return NoAlias(derived()); } } // end namespace Eigen diff --git a/splinter/src/Core/NumTraits.h b/splinter/thirdparty/Eigen/Eigen/src/Core/NumTraits.h similarity index 56% rename from splinter/src/Core/NumTraits.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/NumTraits.h index bac9e50b85..daf4898789 100644 --- a/splinter/src/Core/NumTraits.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/NumTraits.h @@ -12,24 +12,57 @@ namespace Eigen { +namespace internal { + +// default implementation of digits10(), based on numeric_limits if specialized, +// 0 for integer types, and log10(epsilon()) otherwise. +template< typename T, + bool use_numeric_limits = std::numeric_limits::is_specialized, + bool is_integer = NumTraits::IsInteger> +struct default_digits10_impl +{ + static int run() { return std::numeric_limits::digits10; } +}; + +template +struct default_digits10_impl // Floating point +{ + static int run() { + using std::log10; + using std::ceil; + typedef typename NumTraits::Real Real; + return int(ceil(-log10(NumTraits::epsilon()))); + } +}; + +template +struct default_digits10_impl // Integer +{ + static int run() { return 0; } +}; + +} // end namespace internal + /** \class NumTraits * \ingroup Core_Module * * \brief Holds information about the various numeric (i.e. scalar) types allowed by Eigen. * - * \param T the numeric type at hand + * \tparam T the numeric type at hand * * This class stores enums, typedefs and static methods giving information about a numeric type. * * The provided data consists of: - * \li A typedef \a Real, giving the "real part" type of \a T. If \a T is already real, - * then \a Real is just a typedef to \a T. If \a T is \c std::complex then \a Real + * \li A typedef \c Real, giving the "real part" type of \a T. If \a T is already real, + * then \c Real is just a typedef to \a T. If \a T is \c std::complex then \c Real * is a typedef to \a U. - * \li A typedef \a NonInteger, giving the type that should be used for operations producing non-integral values, + * \li A typedef \c NonInteger, giving the type that should be used for operations producing non-integral values, * such as quotients, square roots, etc. If \a T is a floating-point type, then this typedef just gives * \a T again. Note however that many Eigen functions such as internal::sqrt simply refuse to * take integers. Outside of a few cases, Eigen doesn't do automatic type promotion. Thus, this typedef is * only intended as a helper for code that needs to explicitly promote types. + * \li A typedef \c Literal giving the type to use for numeric literals such as "2" or "0.5". For instance, for \c std::complex, Literal is defined as \c U. + * Of course, this type must be fully compatible with \a T. In doubt, just use \a T here. * \li A typedef \a Nested giving the type to use to nest a value inside of the expression tree. If you don't know what * this means, just use \a T here. * \li An enum value \a IsComplex. It is equal to 1 if \a T is a \c std::complex @@ -42,10 +75,14 @@ namespace Eigen { * \li An enum value \a IsSigned. It is equal to \c 1 if \a T is a signed type and to 0 if \a T is unsigned. * \li An enum value \a RequireInitialization. It is equal to \c 1 if the constructor of the numeric type \a T must * be called, and to 0 if it is safe not to call it. Default is 0 if \a T is an arithmetic type, and 1 otherwise. - * \li An epsilon() function which, unlike std::numeric_limits::epsilon(), returns a \a Real instead of a \a T. + * \li An epsilon() function which, unlike std::numeric_limits::epsilon(), + * it returns a \a Real instead of a \a T. * \li A dummy_precision() function returning a weak epsilon value. It is mainly used as a default * value by the fuzzy comparison operators. * \li highest() and lowest() functions returning the highest and lowest possible values respectively. + * \li digits10() function returning the number of decimal digits that can be represented without change. This is + * the analogue of std::numeric_limits::digits10 + * which is used as the default implementation if specialized. */ template struct GenericNumTraits @@ -67,22 +104,47 @@ template struct GenericNumTraits T >::type NonInteger; typedef T Nested; + typedef T Literal; + + EIGEN_DEVICE_FUNC + static inline Real epsilon() + { + return numext::numeric_limits::epsilon(); + } + + EIGEN_DEVICE_FUNC + static inline int digits10() + { + return internal::default_digits10_impl::run(); + } - static inline Real epsilon() { return std::numeric_limits::epsilon(); } + EIGEN_DEVICE_FUNC static inline Real dummy_precision() { // make sure to override this for floating-point types return Real(0); } - 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 { - HasFloatingPoint = !IsInteger - }; - typedef NonInteger FloatingPoint; -#endif + + + EIGEN_DEVICE_FUNC + static inline T highest() { + return (numext::numeric_limits::max)(); + } + + EIGEN_DEVICE_FUNC + static inline T lowest() { + return IsInteger ? (numext::numeric_limits::min)() : (-(numext::numeric_limits::max)()); + } + + EIGEN_DEVICE_FUNC + static inline T infinity() { + return numext::numeric_limits::infinity(); + } + + EIGEN_DEVICE_FUNC + static inline T quiet_NaN() { + return numext::numeric_limits::quiet_NaN(); + } }; template struct NumTraits : GenericNumTraits @@ -91,11 +153,13 @@ template struct NumTraits : GenericNumTraits template<> struct NumTraits : GenericNumTraits { + EIGEN_DEVICE_FUNC static inline float dummy_precision() { return 1e-5f; } }; template<> struct NumTraits : GenericNumTraits { + EIGEN_DEVICE_FUNC static inline double dummy_precision() { return 1e-12; } }; @@ -109,6 +173,7 @@ template struct NumTraits > : GenericNumTraits > { typedef _Real Real; + typedef typename NumTraits<_Real>::Literal Literal; enum { IsComplex = 1, RequireInitialization = NumTraits<_Real>::RequireInitialization, @@ -117,8 +182,12 @@ template struct NumTraits > MulCost = 4 * NumTraits::MulCost + 2 * NumTraits::AddCost }; + EIGEN_DEVICE_FUNC static inline Real epsilon() { return NumTraits::epsilon(); } + EIGEN_DEVICE_FUNC static inline Real dummy_precision() { return NumTraits::dummy_precision(); } + EIGEN_DEVICE_FUNC + static inline int digits10() { return NumTraits::digits10(); } }; template @@ -130,21 +199,50 @@ struct NumTraits > typedef typename NumTraits::NonInteger NonIntegerScalar; typedef Array NonInteger; typedef ArrayType & Nested; - + typedef typename NumTraits::Literal Literal; + enum { IsComplex = NumTraits::IsComplex, IsInteger = NumTraits::IsInteger, IsSigned = NumTraits::IsSigned, RequireInitialization = 1, - ReadCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::ReadCost, - AddCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::AddCost, - MulCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::MulCost + ReadCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * NumTraits::ReadCost, + AddCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * NumTraits::AddCost, + MulCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * NumTraits::MulCost }; - + + EIGEN_DEVICE_FUNC static inline RealScalar epsilon() { return NumTraits::epsilon(); } + EIGEN_DEVICE_FUNC static inline RealScalar dummy_precision() { return NumTraits::dummy_precision(); } + + static inline int digits10() { return NumTraits::digits10(); } +}; + +template<> struct NumTraits + : GenericNumTraits +{ + enum { + RequireInitialization = 1, + ReadCost = HugeCost, + AddCost = HugeCost, + MulCost = HugeCost + }; + + static inline int digits10() { return 0; } + +private: + static inline std::string epsilon(); + static inline std::string dummy_precision(); + static inline std::string lowest(); + static inline std::string highest(); + static inline std::string infinity(); + static inline std::string quiet_NaN(); }; +// Empty specialization for void to allow template specialization based on NumTraits::Real with T==void and SFINAE. +template<> struct NumTraits {}; + } // end namespace Eigen #endif // EIGEN_NUMTRAITS_H diff --git a/splinter/src/Core/PermutationMatrix.h b/splinter/thirdparty/Eigen/Eigen/src/Core/PermutationMatrix.h similarity index 60% rename from splinter/src/Core/PermutationMatrix.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/PermutationMatrix.h index 85ffae2653..b1fb455b98 100644 --- a/splinter/src/Core/PermutationMatrix.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/PermutationMatrix.h @@ -2,7 +2,7 @@ // for linear algebra. // // Copyright (C) 2009 Benoit Jacob -// Copyright (C) 2009-2011 Gael Guennebaud +// Copyright (C) 2009-2015 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 @@ -13,14 +13,18 @@ namespace Eigen { -template class PermutedImpl; +namespace internal { + +enum PermPermProduct_t {PermPermProduct}; + +} // end namespace internal /** \class PermutationBase * \ingroup Core_Module * * \brief Base class for permutations * - * \param Derived the derived class + * \tparam Derived the derived class * * This class is the base class for all expressions representing a permutation matrix, * internally stored as a vector of integers. @@ -38,17 +42,6 @@ template -struct permut_matrix_product_retval; -template -struct permut_sparsematrix_product_retval; -enum PermPermProduct_t {PermPermProduct}; - -} // end namespace internal - template class PermutationBase : public EigenBase { @@ -60,19 +53,20 @@ class PermutationBase : public EigenBase typedef typename Traits::IndicesType IndicesType; enum { Flags = Traits::Flags, - CoeffReadCost = Traits::CoeffReadCost, RowsAtCompileTime = Traits::RowsAtCompileTime, ColsAtCompileTime = Traits::ColsAtCompileTime, MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = Traits::MaxColsAtCompileTime }; - typedef typename Traits::Scalar Scalar; - typedef typename Traits::Index Index; - typedef Matrix + typedef typename Traits::StorageIndex StorageIndex; + typedef Matrix DenseMatrixType; - typedef PermutationMatrix + typedef PermutationMatrix PlainPermutationType; + typedef PlainPermutationType PlainObject; using Base::derived; + typedef Inverse InverseReturnType; + typedef void Scalar; #endif /** Copies the other permutation into *this */ @@ -118,7 +112,7 @@ class PermutationBase : public EigenBase void evalTo(MatrixBase& other) const { other.setZero(); - for (int i=0; i /** Sets *this to be the identity permutation matrix */ void setIdentity() { - for(Index i = 0; i < size(); ++i) + StorageIndex n = StorageIndex(size()); + for(StorageIndex i = 0; i < n; ++i) indices().coeffRef(i) = i; } @@ -163,18 +158,18 @@ class PermutationBase : public EigenBase * * \returns a reference to *this. * - * \warning This is much slower than applyTranspositionOnTheRight(int,int): + * \warning This is much slower than applyTranspositionOnTheRight(Index,Index): * this has linear complexity and requires a lot of branching. * - * \sa applyTranspositionOnTheRight(int,int) + * \sa applyTranspositionOnTheRight(Index,Index) */ Derived& applyTranspositionOnTheLeft(Index i, Index j) { eigen_assert(i>=0 && j>=0 && i * * This is a fast operation, it only consists in swapping two indices. * - * \sa applyTranspositionOnTheLeft(int,int) + * \sa applyTranspositionOnTheLeft(Index,Index) */ Derived& applyTranspositionOnTheRight(Index i, Index j) { @@ -196,16 +191,16 @@ class PermutationBase : public EigenBase /** \returns the inverse permutation matrix. * - * \note \note_try_to_help_rvo + * \note \blank \note_try_to_help_rvo */ - inline Transpose inverse() const - { return derived(); } + inline InverseReturnType inverse() const + { return InverseReturnType(derived()); } /** \returns the tranpose permutation matrix. * - * \note \note_try_to_help_rvo + * \note \blank \note_try_to_help_rvo */ - inline Transpose transpose() const - { return derived(); } + inline InverseReturnType transpose() const + { return InverseReturnType(derived()); } /**** multiplication helpers to hopefully get RVO ****/ @@ -215,13 +210,13 @@ class PermutationBase : public EigenBase template void assignTranspose(const PermutationBase& other) { - for (int i=0; i void assignProduct(const Lhs& lhs, const Rhs& rhs) { eigen_assert(lhs.cols() == rhs.rows()); - for (int i=0; i /** \returns the product permutation matrix. * - * \note \note_try_to_help_rvo + * \note \blank \note_try_to_help_rvo */ template inline PlainPermutationType operator*(const PermutationBase& other) const @@ -237,18 +232,18 @@ class PermutationBase : public EigenBase /** \returns the product of a permutation with another inverse permutation. * - * \note \note_try_to_help_rvo + * \note \blank \note_try_to_help_rvo */ template - inline PlainPermutationType operator*(const Transpose >& other) const + inline PlainPermutationType operator*(const InverseImpl& other) const { return PlainPermutationType(internal::PermPermProduct, *this, other.eval()); } /** \returns the product of an inverse permutation with another permutation. * - * \note \note_try_to_help_rvo + * \note \blank \note_try_to_help_rvo */ template friend - inline PlainPermutationType operator*(const Transpose >& other, const PermutationBase& perm) + inline PlainPermutationType operator*(const InverseImpl& other, const PermutationBase& perm) { return PlainPermutationType(internal::PermPermProduct, other.eval(), perm); } /** \returns the determinant of the permutation matrix, which is either 1 or -1 depending on the parity of the permutation. @@ -284,39 +279,43 @@ class PermutationBase : public EigenBase }; +namespace internal { +template +struct traits > + : traits > +{ + typedef PermutationStorage StorageKind; + typedef Matrix<_StorageIndex, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1> IndicesType; + typedef _StorageIndex StorageIndex; + typedef void Scalar; +}; +} + /** \class PermutationMatrix * \ingroup Core_Module * * \brief Permutation matrix * - * \param SizeAtCompileTime the number of rows/cols, or Dynamic - * \param MaxSizeAtCompileTime the maximum number of rows/cols, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it. - * \param IndexType the interger type of the indices + * \tparam SizeAtCompileTime the number of rows/cols, or Dynamic + * \tparam MaxSizeAtCompileTime the maximum number of rows/cols, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it. + * \tparam _StorageIndex the integer type of the indices * * This class represents a permutation matrix, internally stored as a vector of integers. * * \sa class PermutationBase, class PermutationWrapper, class DiagonalMatrix */ - -namespace internal { -template -struct traits > - : traits > -{ - typedef IndexType Index; - typedef Matrix IndicesType; -}; -} - -template -class PermutationMatrix : public PermutationBase > +template +class PermutationMatrix : public PermutationBase > { typedef PermutationBase Base; typedef internal::traits Traits; public: + typedef const PermutationMatrix& Nested; + #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Traits::IndicesType IndicesType; + typedef typename Traits::StorageIndex StorageIndex; #endif inline PermutationMatrix() @@ -324,8 +323,10 @@ class PermutationMatrix : public PermutationBase::highest()); + } /** Copy constructor. */ template @@ -346,7 +347,7 @@ class PermutationMatrix : public PermutationBase - explicit inline PermutationMatrix(const MatrixBase& a_indices) : m_indices(a_indices) + explicit inline PermutationMatrix(const MatrixBase& indices) : m_indices(indices) {} /** Convert the Transpositions \a tr to a permutation matrix */ @@ -393,10 +394,13 @@ class PermutationMatrix : public PermutationBase - PermutationMatrix(const Transpose >& other) - : m_indices(other.nestedPermutation().size()) + PermutationMatrix(const InverseImpl& other) + : m_indices(other.derived().nestedExpression().size()) { - for (int i=0; i::highest()); + StorageIndex end = StorageIndex(m_indices.size()); + for (StorageIndex i=0; i PermutationMatrix(internal::PermPermProduct_t, const Lhs& lhs, const Rhs& rhs) @@ -413,18 +417,20 @@ class PermutationMatrix : public PermutationBase -struct traits,_PacketAccess> > - : traits > +template +struct traits,_PacketAccess> > + : traits > { - typedef IndexType Index; - typedef Map, _PacketAccess> IndicesType; + typedef PermutationStorage StorageKind; + typedef Map, _PacketAccess> IndicesType; + typedef _StorageIndex StorageIndex; + typedef void Scalar; }; } -template -class Map,_PacketAccess> - : public PermutationBase,_PacketAccess> > +template +class Map,_PacketAccess> + : public PermutationBase,_PacketAccess> > { typedef PermutationBase Base; typedef internal::traits Traits; @@ -432,14 +438,14 @@ class Map, #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Traits::IndicesType IndicesType; - typedef typename IndicesType::Scalar Index; + typedef typename IndicesType::Scalar StorageIndex; #endif - inline Map(const Index* indicesPtr) + inline Map(const StorageIndex* indicesPtr) : m_indices(indicesPtr) {} - inline Map(const Index* indicesPtr, Index size) + inline Map(const StorageIndex* indicesPtr, Index size) : m_indices(indicesPtr,size) {} @@ -474,40 +480,36 @@ class Map, IndicesType m_indices; }; -/** \class PermutationWrapper - * \ingroup Core_Module - * - * \brief Class to view a vector of integers as a permutation matrix - * - * \param _IndicesType the type of the vector of integer (can be any compatible expression) - * - * This class allows to view any vector expression of integers as a permutation matrix. - * - * \sa class PermutationBase, class PermutationMatrix - */ - -struct PermutationStorage {}; - template class TranspositionsWrapper; namespace internal { template struct traits > { typedef PermutationStorage StorageKind; - typedef typename _IndicesType::Scalar Scalar; - typedef typename _IndicesType::Scalar Index; + typedef void Scalar; + typedef typename _IndicesType::Scalar StorageIndex; typedef _IndicesType IndicesType; enum { RowsAtCompileTime = _IndicesType::SizeAtCompileTime, ColsAtCompileTime = _IndicesType::SizeAtCompileTime, - MaxRowsAtCompileTime = IndicesType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = IndicesType::MaxColsAtCompileTime, - Flags = 0, - CoeffReadCost = _IndicesType::CoeffReadCost + MaxRowsAtCompileTime = IndicesType::MaxSizeAtCompileTime, + MaxColsAtCompileTime = IndicesType::MaxSizeAtCompileTime, + Flags = 0 }; }; } +/** \class PermutationWrapper + * \ingroup Core_Module + * + * \brief Class to view a vector of integers as a permutation matrix + * + * \tparam _IndicesType the type of the vector of integer (can be any compatible expression) + * + * This class allows to view any vector expression of integers as a permutation matrix. + * + * \sa class PermutationBase, class PermutationMatrix + */ template class PermutationWrapper : public PermutationBase > { @@ -519,8 +521,8 @@ class PermutationWrapper : public PermutationBase -inline const internal::permut_matrix_product_retval -operator*(const MatrixBase& matrix, - const PermutationBase &permutation) +template +EIGEN_DEVICE_FUNC +const Product +operator*(const MatrixBase &matrix, + const PermutationBase& permutation) { - return internal::permut_matrix_product_retval - - (permutation.derived(), matrix.derived()); + return Product + (matrix.derived(), permutation.derived()); } /** \returns the matrix with the permutation applied to the rows. */ -template -inline const internal::permut_matrix_product_retval - +template +EIGEN_DEVICE_FUNC +const Product operator*(const PermutationBase &permutation, - const MatrixBase& matrix) + const MatrixBase& matrix) { - return internal::permut_matrix_product_retval - - (permutation.derived(), matrix.derived()); + return Product + (permutation.derived(), matrix.derived()); } -namespace internal { -template -struct traits > +template +class InverseImpl + : public EigenBase > { - typedef typename MatrixType::PlainObject ReturnType; -}; - -template -struct permut_matrix_product_retval - : public ReturnByValue > -{ - typedef typename remove_all::type MatrixTypeNestedCleaned; - typedef typename MatrixType::Index Index; - - permut_matrix_product_retval(const PermutationType& perm, const MatrixType& matrix) - : m_permutation(perm), m_matrix(matrix) - {} - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - - template inline void evalTo(Dest& dst) const - { - const Index n = Side==OnTheLeft ? rows() : cols(); - // FIXME we need an is_same for expression that is not sensitive to constness. For instance - // is_same_xpr, Block >::value should be true. - if( is_same::value - && blas_traits::HasUsableDirectAccess - && blas_traits::HasUsableDirectAccess - && extract_data(dst) == extract_data(m_matrix)) - { - // apply the permutation inplace - Matrix mask(m_permutation.size()); - mask.fill(false); - Index r = 0; - while(r < m_permutation.size()) - { - // search for the next seed - while(r=m_permutation.size()) - break; - // we got one, let's follow it until we are back to the seed - Index k0 = r++; - Index kPrev = k0; - mask.coeffRef(k0) = true; - for(Index k=m_permutation.indices().coeff(k0); k!=k0; k=m_permutation.indices().coeff(k)) - { - Block(dst, k) - .swap(Block - (dst,((Side==OnTheLeft) ^ Transposed) ? k0 : kPrev)); - - mask.coeffRef(k) = true; - kPrev = k; - } - } - } - else - { - for(int i = 0; i < n; ++i) - { - Block - (dst, ((Side==OnTheLeft) ^ Transposed) ? m_permutation.indices().coeff(i) : i) - - = - - Block - (m_matrix, ((Side==OnTheRight) ^ Transposed) ? m_permutation.indices().coeff(i) : i); - } - } - } - - protected: - const PermutationType& m_permutation; - typename MatrixType::Nested m_matrix; -}; - -/* Template partial specialization for transposed/inverse permutations */ - -template -struct traits > > - : traits -{}; - -} // end namespace internal - -template -class Transpose > - : public EigenBase > > -{ - typedef Derived PermutationType; - typedef typename PermutationType::IndicesType IndicesType; typedef typename PermutationType::PlainPermutationType PlainPermutationType; + typedef internal::traits PermTraits; + protected: + InverseImpl() {} public: + typedef Inverse InverseType; + using EigenBase >::derived; #ifndef EIGEN_PARSED_BY_DOXYGEN - typedef internal::traits Traits; - typedef typename Derived::DenseMatrixType DenseMatrixType; + typedef typename PermutationType::DenseMatrixType DenseMatrixType; enum { - Flags = Traits::Flags, - CoeffReadCost = Traits::CoeffReadCost, - RowsAtCompileTime = Traits::RowsAtCompileTime, - ColsAtCompileTime = Traits::ColsAtCompileTime, - MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = Traits::MaxColsAtCompileTime + RowsAtCompileTime = PermTraits::RowsAtCompileTime, + ColsAtCompileTime = PermTraits::ColsAtCompileTime, + MaxRowsAtCompileTime = PermTraits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = PermTraits::MaxColsAtCompileTime }; - typedef typename Traits::Scalar Scalar; #endif - Transpose(const PermutationType& p) : m_permutation(p) {} - - inline int rows() const { return m_permutation.rows(); } - inline int cols() const { return m_permutation.cols(); } - #ifndef EIGEN_PARSED_BY_DOXYGEN template void evalTo(MatrixBase& other) const { other.setZero(); - for (int i=0; i friend - inline const internal::permut_matrix_product_retval - operator*(const MatrixBase& matrix, const Transpose& trPerm) + const Product + operator*(const MatrixBase& matrix, const InverseType& trPerm) { - return internal::permut_matrix_product_retval(trPerm.m_permutation, matrix.derived()); + return Product(matrix.derived(), trPerm.derived()); } /** \returns the matrix with the inverse permutation applied to the rows. */ template - inline const internal::permut_matrix_product_retval + const Product operator*(const MatrixBase& matrix) const { - return internal::permut_matrix_product_retval(m_permutation, matrix.derived()); + return Product(derived(), matrix.derived()); } - - const PermutationType& nestedPermutation() const { return m_permutation; } - - protected: - const PermutationType& m_permutation; }; template @@ -716,6 +622,12 @@ const PermutationWrapper MatrixBase::asPermutation() con return derived(); } +namespace internal { + +template<> struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; + +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_PERMUTATIONMATRIX_H diff --git a/splinter/src/Core/PlainObjectBase.h b/splinter/thirdparty/Eigen/Eigen/src/Core/PlainObjectBase.h similarity index 67% rename from splinter/src/Core/PlainObjectBase.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/PlainObjectBase.h index a4e4af4a7b..1dc7e223af 100644 --- a/splinter/src/Core/PlainObjectBase.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/PlainObjectBase.h @@ -28,6 +28,7 @@ namespace internal { template struct check_rows_cols_for_overflow { template + EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE void run(Index, Index) { } @@ -35,11 +36,12 @@ template struct check_rows_cols_for_overflow { template<> struct check_rows_cols_for_overflow { template + EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE void run(Index rows, Index cols) { // http://hg.mozilla.org/mozilla-central/file/6c8a909977d3/xpcom/ds/CheckedInt.h#l242 // we assume Index is signed - Index max_index = (size_t(1) << (8 * sizeof(Index) - 1)) - 1; // assume Index is signed + Index max_index = (std::size_t(1) << (8 * sizeof(Index) - 1)) - 1; // assume Index is signed bool error = (rows == 0 || cols == 0) ? false : (rows > max_index / cols); if (error) @@ -56,33 +58,41 @@ template struct m } // 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 - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_PLAINOBJECTBASE_PLUGIN. - * - * \sa \ref TopicClassHierarchy - */ #ifdef EIGEN_PARSED_BY_DOXYGEN -namespace internal { +namespace doxygen { -// this is a warkaround to doxygen not being able to understand the inheritence logic +// This is a workaround to doxygen not being able to understand the inheritance logic // when it is hidden by the dense_xpr_base helper struct. -template struct dense_xpr_base_dispatcher_for_doxygen;// : public MatrixBase {}; +// Moreover, doxygen fails to include members that are not documented in the declaration body of +// MatrixBase if we inherits MatrixBase >, +// this is why we simply inherits MatrixBase, though this does not make sense. + +/** This class is just a workaround for Doxygen and it does not not actually exist. */ +template struct dense_xpr_base_dispatcher; /** 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 > {}; +struct dense_xpr_base_dispatcher > + : 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 > {}; +struct dense_xpr_base_dispatcher > + : public ArrayBase {}; -} // namespace internal +} // namespace doxygen +/** \class PlainObjectBase + * \ingroup Core_Module + * \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 + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_PLAINOBJECTBASE_PLUGIN. + * + * \tparam Derived is the derived type, e.g., a Matrix or Array + * + * \sa \ref TopicClassHierarchy + */ template -class PlainObjectBase : public internal::dense_xpr_base_dispatcher_for_doxygen +class PlainObjectBase : public doxygen::dense_xpr_base_dispatcher #else template class PlainObjectBase : public internal::dense_xpr_base::type @@ -93,8 +103,8 @@ class PlainObjectBase : public internal::dense_xpr_base::type typedef typename internal::dense_xpr_base::type Base; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; typedef Derived DenseType; @@ -113,28 +123,40 @@ class PlainObjectBase : public internal::dense_xpr_base::type typedef Eigen::Map MapType; friend class Eigen::Map; typedef const Eigen::Map ConstMapType; - friend class Eigen::Map; - typedef Eigen::Map AlignedMapType; - friend class Eigen::Map; - typedef const Eigen::Map ConstAlignedMapType; +#if EIGEN_MAX_ALIGN_BYTES>0 + // for EIGEN_MAX_ALIGN_BYTES==0, AlignedMax==Unaligned, and many compilers generate warnings for friend-ing a class twice. + friend class Eigen::Map; + friend class Eigen::Map; +#endif + typedef Eigen::Map AlignedMapType; + typedef const Eigen::Map ConstAlignedMapType; template struct StridedMapType { typedef Eigen::Map type; }; template struct StridedConstMapType { typedef Eigen::Map type; }; - template struct StridedAlignedMapType { typedef Eigen::Map type; }; - template struct StridedConstAlignedMapType { typedef Eigen::Map type; }; + template struct StridedAlignedMapType { typedef Eigen::Map type; }; + template struct StridedConstAlignedMapType { typedef Eigen::Map type; }; protected: DenseStorage m_storage; public: - enum { NeedsToAlign = SizeAtCompileTime != Dynamic && (internal::traits::Flags & AlignedBit) != 0 }; + enum { NeedsToAlign = (SizeAtCompileTime != Dynamic) && (internal::traits::Alignment>0) }; EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) + EIGEN_DEVICE_FUNC Base& base() { return *static_cast(this); } + EIGEN_DEVICE_FUNC const Base& base() const { return *static_cast(this); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return m_storage.rows(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_storage.cols(); } + /** This is an overloaded version of DenseCoeffsBase::coeff(Index,Index) const + * provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts. + * + * See DenseCoeffsBase::coeff(Index) const for details. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index rowId, Index colId) const { if(Flags & RowMajorBit) @@ -143,11 +165,21 @@ class PlainObjectBase : public internal::dense_xpr_base::type return m_storage.data()[rowId + colId * m_storage.rows()]; } + /** This is an overloaded version of DenseCoeffsBase::coeff(Index) const + * provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts. + * + * See DenseCoeffsBase::coeff(Index) const for details. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const { return m_storage.data()[index]; } + /** This is an overloaded version of DenseCoeffsBase::coeffRef(Index,Index) const + * provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts. + * + * See DenseCoeffsBase::coeffRef(Index,Index) const for details. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index rowId, Index colId) { if(Flags & RowMajorBit) @@ -156,11 +188,19 @@ class PlainObjectBase : public internal::dense_xpr_base::type return m_storage.data()[rowId + colId * m_storage.rows()]; } + /** This is an overloaded version of DenseCoeffsBase::coeffRef(Index) const + * provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts. + * + * See DenseCoeffsBase::coeffRef(Index) const for details. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { return m_storage.data()[index]; } + /** This is the const version of coeffRef(Index,Index) which is thus synonym of coeff(Index,Index). + * It is provided for convenience. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeffRef(Index rowId, Index colId) const { if(Flags & RowMajorBit) @@ -169,6 +209,9 @@ class PlainObjectBase : public internal::dense_xpr_base::type return m_storage.data()[rowId + colId * m_storage.rows()]; } + /** This is the const version of coeffRef(Index) which is thus synonym of coeff(Index). + * It is provided for convenience. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeffRef(Index index) const { return m_storage.data()[index]; @@ -209,11 +252,11 @@ class PlainObjectBase : public internal::dense_xpr_base::type } /** \returns a const pointer to the data array of this matrix */ - EIGEN_STRONG_INLINE const Scalar *data() const + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar *data() const { return m_storage.data(); } /** \returns a pointer to the data array of this matrix */ - EIGEN_STRONG_INLINE Scalar *data() + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar *data() { return m_storage.data(); } /** Resizes \c *this to a \a rows x \a cols matrix. @@ -232,22 +275,22 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \sa resize(Index) for vectors, resize(NoChange_t, Index), resize(Index, NoChange_t) */ - EIGEN_STRONG_INLINE void resize(Index nbRows, Index nbCols) - { - eigen_assert( EIGEN_IMPLIES(RowsAtCompileTime!=Dynamic,nbRows==RowsAtCompileTime) - && EIGEN_IMPLIES(ColsAtCompileTime!=Dynamic,nbCols==ColsAtCompileTime) - && EIGEN_IMPLIES(RowsAtCompileTime==Dynamic && MaxRowsAtCompileTime!=Dynamic,nbRows<=MaxRowsAtCompileTime) - && EIGEN_IMPLIES(ColsAtCompileTime==Dynamic && MaxColsAtCompileTime!=Dynamic,nbCols<=MaxColsAtCompileTime) - && nbRows>=0 && nbCols>=0 && "Invalid sizes when resizing a matrix or array."); - internal::check_rows_cols_for_overflow::run(nbRows, nbCols); + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void resize(Index rows, Index cols) + { + eigen_assert( EIGEN_IMPLIES(RowsAtCompileTime!=Dynamic,rows==RowsAtCompileTime) + && EIGEN_IMPLIES(ColsAtCompileTime!=Dynamic,cols==ColsAtCompileTime) + && EIGEN_IMPLIES(RowsAtCompileTime==Dynamic && MaxRowsAtCompileTime!=Dynamic,rows<=MaxRowsAtCompileTime) + && EIGEN_IMPLIES(ColsAtCompileTime==Dynamic && MaxColsAtCompileTime!=Dynamic,cols<=MaxColsAtCompileTime) + && rows>=0 && cols>=0 && "Invalid sizes when resizing a matrix or array."); + internal::check_rows_cols_for_overflow::run(rows, cols); #ifdef EIGEN_INITIALIZE_COEFFS - Index size = nbRows*nbCols; + Index size = rows*cols; bool size_changed = size != this->size(); - m_storage.resize(size, nbRows, nbCols); + m_storage.resize(size, rows, cols); if(size_changed) EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED #else - internal::check_rows_cols_for_overflow::run(nbRows, nbCols); - m_storage.resize(nbRows*nbCols, nbRows, nbCols); + m_storage.resize(rows*cols, rows, cols); #endif } @@ -262,6 +305,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \sa resize(Index,Index), resize(NoChange_t, Index), resize(Index, NoChange_t) */ + EIGEN_DEVICE_FUNC inline void resize(Index size) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(PlainObjectBase) @@ -286,9 +330,10 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \sa resize(Index,Index) */ - inline void resize(NoChange_t, Index nbCols) + EIGEN_DEVICE_FUNC + inline void resize(NoChange_t, Index cols) { - resize(rows(), nbCols); + resize(rows(), cols); } /** Resizes the matrix, changing only the number of rows. For the parameter of type NoChange_t, just pass the special value \c NoChange @@ -299,9 +344,10 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \sa resize(Index,Index) */ - inline void resize(Index nbRows, NoChange_t) + EIGEN_DEVICE_FUNC + inline void resize(Index rows, NoChange_t) { - resize(nbRows, cols()); + resize(rows, cols()); } /** Resizes \c *this to have the same dimensions as \a other. @@ -312,6 +358,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type * remain row-vectors and vectors remain vectors. */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resizeLike(const EigenBase& _other) { const OtherDerived& other = _other.derived(); @@ -339,9 +386,10 @@ class PlainObjectBase : public internal::dense_xpr_base::type * Matrices are resized relative to the top-left element. In case values need to be * appended to the matrix they will be uninitialized. */ - EIGEN_STRONG_INLINE void conservativeResize(Index nbRows, Index nbCols) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void conservativeResize(Index rows, Index cols) { - internal::conservative_resize_like_impl::run(*this, nbRows, nbCols); + internal::conservative_resize_like_impl::run(*this, rows, cols); } /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. @@ -351,10 +399,11 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * In case the matrix is growing, new rows will be uninitialized. */ - EIGEN_STRONG_INLINE void conservativeResize(Index nbRows, NoChange_t) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void conservativeResize(Index rows, NoChange_t) { // Note: see the comment in conservativeResize(Index,Index) - conservativeResize(nbRows, cols()); + conservativeResize(rows, cols()); } /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. @@ -364,10 +413,11 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * In case the matrix is growing, new columns will be uninitialized. */ - EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, Index nbCols) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, Index cols) { // Note: see the comment in conservativeResize(Index,Index) - conservativeResize(rows(), nbCols); + conservativeResize(rows(), cols); } /** Resizes the vector to \a size while retaining old values. @@ -378,6 +428,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * When values are appended, they will be uninitialized. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void conservativeResize(Index size) { internal::conservative_resize_like_impl::run(*this, size); @@ -393,6 +444,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type * appended to the matrix they will copied from \c other. */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void conservativeResizeLike(const DenseBase& other) { internal::conservative_resize_like_impl::run(*this, other); @@ -401,6 +453,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const PlainObjectBase& other) { return _set(other); @@ -408,6 +461,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type /** \sa MatrixBase::lazyAssign() */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& lazyAssign(const DenseBase& other) { _resize_to_match(other); @@ -415,12 +469,18 @@ class PlainObjectBase : public internal::dense_xpr_base::type } template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const ReturnByValue& func) { resize(func.rows(), func.cols()); return Base::operator=(func); } + // Prevent user from trying to instantiate PlainObjectBase objects + // by making all its constructor protected. See bug 1074. + protected: + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PlainObjectBase() : m_storage() { // _check_template_params(); @@ -430,20 +490,23 @@ class PlainObjectBase : public internal::dense_xpr_base::type #ifndef EIGEN_PARSED_BY_DOXYGEN // FIXME is it still needed ? /** \internal */ - PlainObjectBase(internal::constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC + explicit PlainObjectBase(internal::constructor_without_unaligned_array_assert) : m_storage(internal::constructor_without_unaligned_array_assert()) { // _check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } #endif -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - PlainObjectBase(PlainObjectBase&& other) +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + PlainObjectBase(PlainObjectBase&& other) EIGEN_NOEXCEPT : m_storage( std::move(other.m_storage) ) { } - PlainObjectBase& operator=(PlainObjectBase&& other) + EIGEN_DEVICE_FUNC + PlainObjectBase& operator=(PlainObjectBase&& other) EIGEN_NOEXCEPT { using std::swap; swap(m_storage, other.m_storage); @@ -452,31 +515,56 @@ class PlainObjectBase : public internal::dense_xpr_base::type #endif /** Copy constructor */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PlainObjectBase(const PlainObjectBase& other) - : m_storage() + : Base(), m_storage(other.m_storage) { } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PlainObjectBase(Index size, Index rows, Index cols) + : m_storage(size, rows, cols) { - _check_template_params(); - lazyAssign(other); +// _check_template_params(); +// EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } + /** \sa PlainObjectBase::operator=(const EigenBase&) */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PlainObjectBase(const DenseBase &other) : m_storage() { _check_template_params(); - lazyAssign(other); + resizeLike(other); + _set_noalias(other); } - EIGEN_STRONG_INLINE PlainObjectBase(Index a_size, Index nbRows, Index nbCols) - : m_storage(a_size, nbRows, nbCols) + /** \sa PlainObjectBase::operator=(const EigenBase&) */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PlainObjectBase(const EigenBase &other) + : m_storage() { -// _check_template_params(); -// EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + _check_template_params(); + resizeLike(other); + *this = other.derived(); + } + /** \brief Copy constructor with in-place evaluation */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PlainObjectBase(const ReturnByValue& other) + { + _check_template_params(); + // FIXME this does not automatically transpose vectors if necessary + resize(other.rows(), other.cols()); + other.evalTo(this->derived()); } - /** \copydoc MatrixBase::operator=(const EigenBase&) + public: + + /** \brief Copies the generic expression \a other into *this. + * \copydetails DenseBase::operator=(const EigenBase &other) */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const EigenBase &other) { _resize_to_match(other); @@ -484,21 +572,15 @@ class PlainObjectBase : public internal::dense_xpr_base::type return this->derived(); } - /** \sa MatrixBase::operator=(const EigenBase&) */ - template - EIGEN_STRONG_INLINE PlainObjectBase(const EigenBase &other) - : m_storage(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) - { - _check_template_params(); - internal::check_rows_cols_for_overflow::run(other.derived().rows(), other.derived().cols()); - Base::operator=(other.derived()); - } - /** \name Map * These are convenience functions returning Map objects. The Map() static functions return unaligned Map objects, * while the AlignedMap() functions return aligned Map objects and thus should be called only with 16-byte-aligned * \a data pointers. * + * Here is an example using strides: + * \include Matrix_Map_stride.cpp + * Output: \verbinclude Matrix_Map_stride.out + * * \see class Map */ //@{ @@ -568,16 +650,16 @@ class PlainObjectBase : public internal::dense_xpr_base::type //@} using Base::setConstant; - Derived& setConstant(Index size, const Scalar& value); - Derived& setConstant(Index rows, Index cols, const Scalar& value); + EIGEN_DEVICE_FUNC Derived& setConstant(Index size, const Scalar& val); + EIGEN_DEVICE_FUNC Derived& setConstant(Index rows, Index cols, const Scalar& val); using Base::setZero; - Derived& setZero(Index size); - Derived& setZero(Index rows, Index cols); + EIGEN_DEVICE_FUNC Derived& setZero(Index size); + EIGEN_DEVICE_FUNC Derived& setZero(Index rows, Index cols); using Base::setOnes; - Derived& setOnes(Index size); - Derived& setOnes(Index rows, Index cols); + EIGEN_DEVICE_FUNC Derived& setOnes(Index size); + EIGEN_DEVICE_FUNC Derived& setOnes(Index rows, Index cols); using Base::setRandom; Derived& setRandom(Index size); @@ -596,6 +678,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type * remain row-vectors and vectors remain vectors. */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _resize_to_match(const EigenBase& other) { #ifdef EIGEN_NO_AUTOMATIC_RESIZING @@ -603,8 +686,6 @@ class PlainObjectBase : public internal::dense_xpr_base::type : (rows() == other.rows() && cols() == other.cols()))) && "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined"); EIGEN_ONLY_USED_FOR_DEBUG(other); - if(this->size()==0) - resizeLike(other); #else resizeLike(other); #endif @@ -624,25 +705,23 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \internal */ + // aliasing is dealt once in internall::call_assignment + // so at this stage we have to assume aliasing... and resising has to be done later. template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& _set(const DenseBase& other) { - _set_selector(other.derived(), typename internal::conditional(int(OtherDerived::Flags) & EvalBeforeAssigningBit), internal::true_type, internal::false_type>::type()); + internal::call_assignment(this->derived(), other.derived()); return this->derived(); } - template - EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::true_type&) { _set_noalias(other.eval()); } - - template - EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::false_type&) { _set_noalias(other); } - /** \internal Like _set() but additionally makes the assumption that no aliasing effect can happen (which * is the case when creating a new matrix) so one can enforce lazy evaluation. * * \sa operator=(const MatrixBase&), _set() */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& _set_noalias(const DenseBase& other) { // I don't think we need this resize call since the lazyAssign will anyways resize @@ -650,40 +729,175 @@ class PlainObjectBase : public internal::dense_xpr_base::type //_resize_to_match(other); // the 'false' below means to enforce lazy evaluation. We don't use lazyAssign() because // it wouldn't allow to copy a row-vector into a column-vector. - return internal::assign_selector::run(this->derived(), other.derived()); + internal::call_assignment_no_alias(this->derived(), other.derived(), internal::assign_op()); + return this->derived(); } template - EIGEN_STRONG_INLINE void _init2(Index nbRows, Index nbCols, typename internal::enable_if::type* = 0) + EIGEN_DEVICE_FUNC + 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) - resize(nbRows,nbCols); + resize(rows,cols); + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init2(const T0& val0, const T1& val1, typename internal::enable_if::type* = 0) + { + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 2) + m_storage.data()[0] = Scalar(val0); + m_storage.data()[1] = Scalar(val1); } + template - EIGEN_STRONG_INLINE void _init2(const Scalar& val0, const Scalar& val1, typename internal::enable_if::type* = 0) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init2(const Index& val0, const Index& val1, + typename internal::enable_if< (!internal::is_same::value) + && (internal::is_same::value) + && (internal::is_same::value) + && Base::SizeAtCompileTime==2,T1>::type* = 0) { EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 2) + m_storage.data()[0] = Scalar(val0); + m_storage.data()[1] = Scalar(val1); + } + + // The argument is convertible to the Index type and we either have a non 1x1 Matrix, or a dynamic-sized Array, + // then the argument is meant to be the size of the object. + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(Index size, typename internal::enable_if< (Base::SizeAtCompileTime!=1 || !internal::is_convertible::value) + && ((!internal::is_same::XprKind,ArrayXpr>::value || Base::SizeAtCompileTime==Dynamic)),T>::type* = 0) + { + // NOTE MSVC 2008 complains if we directly put bool(NumTraits::IsInteger) as the EIGEN_STATIC_ASSERT argument. + const bool is_integer = NumTraits::IsInteger; + EIGEN_UNUSED_VARIABLE(is_integer); + EIGEN_STATIC_ASSERT(is_integer, + FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED) + resize(size); + } + + // We have a 1x1 matrix/array => the argument is interpreted as the value of the unique coefficient (case where scalar type can be implicitely converted) + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Scalar& val0, typename internal::enable_if::value,T>::type* = 0) + { + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 1) m_storage.data()[0] = val0; - m_storage.data()[1] = val1; + } + + // We have a 1x1 matrix/array => the argument is interpreted as the value of the unique coefficient (case where scalar type match the index type) + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Index& val0, + typename internal::enable_if< (!internal::is_same::value) + && (internal::is_same::value) + && Base::SizeAtCompileTime==1 + && internal::is_convertible::value,T*>::type* = 0) + { + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 1) + m_storage.data()[0] = Scalar(val0); } + // Initialize a fixed size matrix from a pointer to raw data + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Scalar* data){ + this->_set_noalias(ConstMapType(data)); + } + + // Initialize an arbitrary matrix from a dense expression + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const DenseBase& other){ + this->_set_noalias(other); + } + + // Initialize an arbitrary matrix from an object convertible to the Derived type. + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Derived& other){ + this->_set_noalias(other); + } + + // Initialize an arbitrary matrix from a generic Eigen expression + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const EigenBase& other){ + this->derived() = other; + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const ReturnByValue& other) + { + resize(other.rows(), other.cols()); + other.evalTo(this->derived()); + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const RotationBase& r) + { + this->derived() = r; + } + + // For fixed-size Array + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Scalar& val0, + typename internal::enable_if< Base::SizeAtCompileTime!=Dynamic + && Base::SizeAtCompileTime!=1 + && internal::is_convertible::value + && internal::is_same::XprKind,ArrayXpr>::value,T>::type* = 0) + { + Base::setConstant(val0); + } + + // For fixed-size Array + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Index& val0, + typename internal::enable_if< (!internal::is_same::value) + && (internal::is_same::value) + && Base::SizeAtCompileTime!=Dynamic + && Base::SizeAtCompileTime!=1 + && internal::is_convertible::value + && internal::is_same::XprKind,ArrayXpr>::value,T*>::type* = 0) + { + Base::setConstant(val0); + } + template friend struct internal::matrix_swap_impl; - /** \internal generic implementation of swap for dense storage since for dynamic-sized matrices of same type it is enough to swap the - * data pointers. + public: + +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal + * \brief Override DenseBase::swap() since for dynamic-sized matrices + * of same type it is enough to swap the data pointers. */ template - void _swap(DenseBase const & other) + EIGEN_DEVICE_FUNC + void swap(DenseBase & other) { enum { SwapPointers = internal::is_same::value && Base::SizeAtCompileTime==Dynamic }; - internal::matrix_swap_impl::run(this->derived(), other.const_cast_derived()); + internal::matrix_swap_impl::run(this->derived(), other.derived()); } - - public: -#ifndef EIGEN_PARSED_BY_DOXYGEN + + /** \internal + * \brief const version forwarded to DenseBase::swap + */ + template + EIGEN_DEVICE_FUNC + void swap(DenseBase const & other) + { Base::swap(other.derived()); } + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void _check_template_params() { EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor) @@ -697,10 +911,9 @@ class PlainObjectBase : public internal::dense_xpr_base::type && (Options & (DontAlign|RowMajor)) == Options), INVALID_MATRIX_TEMPLATE_PARAMETERS) } -#endif -private: - enum { ThisConstantIsPrivateInPlainObjectBase }; + enum { IsPlainObjectBase = 1 }; +#endif }; namespace internal { @@ -708,7 +921,6 @@ namespace internal { template struct conservative_resize_like_impl { - typedef typename Derived::Index Index; static void run(DenseBase& _this, Index rows, Index cols) { if (_this.rows() == rows && _this.cols() == cols) return; @@ -724,8 +936,8 @@ struct conservative_resize_like_impl { // The storage order does not allow us to use reallocation. typename Derived::PlainObject tmp(rows,cols); - const Index common_rows = (std::min)(rows, _this.rows()); - const Index common_cols = (std::min)(cols, _this.cols()); + const Index common_rows = numext::mini(rows, _this.rows()); + const Index common_cols = numext::mini(cols, _this.cols()); tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols); _this.derived().swap(tmp); } @@ -758,8 +970,8 @@ struct conservative_resize_like_impl { // The storage order does not allow us to use reallocation. typename Derived::PlainObject tmp(other); - const Index common_rows = (std::min)(tmp.rows(), _this.rows()); - const Index common_cols = (std::min)(tmp.cols(), _this.cols()); + const Index common_rows = numext::mini(tmp.rows(), _this.rows()); + const Index common_cols = numext::mini(tmp.cols(), _this.cols()); tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols); _this.derived().swap(tmp); } @@ -774,7 +986,6 @@ struct conservative_resize_like_impl { using conservative_resize_like_impl::run; - typedef typename Derived::Index Index; static void run(DenseBase& _this, Index size) { const Index new_rows = Derived::RowsAtCompileTime==1 ? 1 : size; @@ -800,6 +1011,7 @@ struct conservative_resize_like_impl template struct matrix_swap_impl { + EIGEN_DEVICE_FUNC static inline void run(MatrixTypeA& a, MatrixTypeB& b) { a.base().swap(b); @@ -809,6 +1021,7 @@ struct matrix_swap_impl template struct matrix_swap_impl { + EIGEN_DEVICE_FUNC static inline void run(MatrixTypeA& a, MatrixTypeB& b) { static_cast(a).m_storage.swap(static_cast(b).m_storage); diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/Product.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Product.h new file mode 100644 index 0000000000..676c480277 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Product.h @@ -0,0 +1,186 @@ +// 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_PRODUCT_H +#define EIGEN_PRODUCT_H + +namespace Eigen { + +template class ProductImpl; + +namespace internal { + +template +struct traits > +{ + typedef typename remove_all::type LhsCleaned; + typedef typename remove_all::type RhsCleaned; + typedef traits LhsTraits; + typedef traits RhsTraits; + + typedef MatrixXpr XprKind; + + typedef typename ScalarBinaryOpTraits::Scalar, typename traits::Scalar>::ReturnType Scalar; + typedef typename product_promote_storage_type::ret>::ret StorageKind; + typedef typename promote_index_type::type StorageIndex; + + enum { + RowsAtCompileTime = LhsTraits::RowsAtCompileTime, + ColsAtCompileTime = RhsTraits::ColsAtCompileTime, + MaxRowsAtCompileTime = LhsTraits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = RhsTraits::MaxColsAtCompileTime, + + // FIXME: only needed by GeneralMatrixMatrixTriangular + InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(LhsTraits::ColsAtCompileTime, RhsTraits::RowsAtCompileTime), + + // The storage order is somewhat arbitrary here. The correct one will be determined through the evaluator. + Flags = (MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1) ? RowMajorBit + : (MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1) ? 0 + : ( ((LhsTraits::Flags&NoPreferredStorageOrderBit) && (RhsTraits::Flags&RowMajorBit)) + || ((RhsTraits::Flags&NoPreferredStorageOrderBit) && (LhsTraits::Flags&RowMajorBit)) ) ? RowMajorBit + : NoPreferredStorageOrderBit + }; +}; + +} // end namespace internal + +/** \class Product + * \ingroup Core_Module + * + * \brief Expression of the product of two arbitrary matrices or vectors + * + * \tparam _Lhs the type of the left-hand side expression + * \tparam _Rhs the type of the right-hand side expression + * + * This class represents an expression of the product of two arbitrary matrices. + * + * The other template parameters are: + * \tparam Option can be DefaultProduct, AliasFreeProduct, or LazyProduct + * + */ +template +class Product : public ProductImpl<_Lhs,_Rhs,Option, + typename internal::product_promote_storage_type::StorageKind, + typename internal::traits<_Rhs>::StorageKind, + internal::product_type<_Lhs,_Rhs>::ret>::ret> +{ + public: + + typedef _Lhs Lhs; + typedef _Rhs Rhs; + + typedef typename ProductImpl< + Lhs, Rhs, Option, + typename internal::product_promote_storage_type::StorageKind, + typename internal::traits::StorageKind, + internal::product_type::ret>::ret>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(Product) + + typedef typename internal::ref_selector::type LhsNested; + typedef typename internal::ref_selector::type RhsNested; + typedef typename internal::remove_all::type LhsNestedCleaned; + typedef typename internal::remove_all::type RhsNestedCleaned; + + EIGEN_DEVICE_FUNC Product(const Lhs& lhs, const Rhs& rhs) : m_lhs(lhs), m_rhs(rhs) + { + eigen_assert(lhs.cols() == rhs.rows() + && "invalid matrix product" + && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); } + + EIGEN_DEVICE_FUNC const LhsNestedCleaned& lhs() const { return m_lhs; } + EIGEN_DEVICE_FUNC const RhsNestedCleaned& rhs() const { return m_rhs; } + + protected: + + LhsNested m_lhs; + RhsNested m_rhs; +}; + +namespace internal { + +template::ret> +class dense_product_base + : public internal::dense_xpr_base >::type +{}; + +/** Convertion to scalar for inner-products */ +template +class dense_product_base + : public internal::dense_xpr_base >::type +{ + typedef Product ProductXpr; + typedef typename internal::dense_xpr_base::type Base; +public: + using Base::derived; + typedef typename Base::Scalar Scalar; + + EIGEN_STRONG_INLINE operator const Scalar() const + { + return internal::evaluator(derived()).coeff(0,0); + } +}; + +} // namespace internal + +// Generic API dispatcher +template +class ProductImpl : public internal::generic_xpr_base, MatrixXpr, StorageKind>::type +{ + public: + typedef typename internal::generic_xpr_base, MatrixXpr, StorageKind>::type Base; +}; + +template +class ProductImpl + : public internal::dense_product_base +{ + typedef Product Derived; + + public: + + typedef typename internal::dense_product_base Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Derived) + protected: + enum { + IsOneByOne = (RowsAtCompileTime == 1 || RowsAtCompileTime == Dynamic) && + (ColsAtCompileTime == 1 || ColsAtCompileTime == Dynamic), + EnableCoeff = IsOneByOne || Option==LazyProduct + }; + + public: + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index row, Index col) const + { + EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS); + eigen_assert( (Option==LazyProduct) || (this->rows() == 1 && this->cols() == 1) ); + + return internal::evaluator(derived()).coeff(row,col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index i) const + { + EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS); + eigen_assert( (Option==LazyProduct) || (this->rows() == 1 && this->cols() == 1) ); + + return internal::evaluator(derived()).coeff(i); + } + + +}; + +} // end namespace Eigen + +#endif // EIGEN_PRODUCT_H diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/ProductEvaluators.h b/splinter/thirdparty/Eigen/Eigen/src/Core/ProductEvaluators.h new file mode 100644 index 0000000000..9b99bd7696 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/ProductEvaluators.h @@ -0,0 +1,1112 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2011 Jitse Niesen +// +// 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_PRODUCTEVALUATORS_H +#define EIGEN_PRODUCTEVALUATORS_H + +namespace Eigen { + +namespace internal { + +/** \internal + * Evaluator of a product expression. + * Since products require special treatments to handle all possible cases, + * we simply deffer the evaluation logic to a product_evaluator class + * which offers more partial specialization possibilities. + * + * \sa class product_evaluator + */ +template +struct evaluator > + : public product_evaluator > +{ + typedef Product XprType; + typedef product_evaluator Base; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr) : Base(xpr) {} +}; + +// Catch "scalar * ( A * B )" and transform it to "(A*scalar) * B" +// TODO we should apply that rule only if that's really helpful +template +struct evaluator_assume_aliasing, + const CwiseNullaryOp, Plain1>, + const Product > > +{ + static const bool value = true; +}; +template +struct evaluator, + const CwiseNullaryOp, Plain1>, + const Product > > + : public evaluator > +{ + typedef CwiseBinaryOp, + const CwiseNullaryOp, Plain1>, + const Product > XprType; + typedef evaluator > Base; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr) + : Base(xpr.lhs().functor().m_other * xpr.rhs().lhs() * xpr.rhs().rhs()) + {} +}; + + +template +struct evaluator, DiagIndex> > + : public evaluator, DiagIndex> > +{ + typedef Diagonal, DiagIndex> XprType; + typedef evaluator, DiagIndex> > Base; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr) + : Base(Diagonal, DiagIndex>( + Product(xpr.nestedExpression().lhs(), xpr.nestedExpression().rhs()), + xpr.index() )) + {} +}; + + +// Helper class to perform a matrix product with the destination at hand. +// Depending on the sizes of the factors, there are different evaluation strategies +// as controlled by internal::product_type. +template< typename Lhs, typename Rhs, + typename LhsShape = typename evaluator_traits::Shape, + typename RhsShape = typename evaluator_traits::Shape, + int ProductType = internal::product_type::value> +struct generic_product_impl; + +template +struct evaluator_assume_aliasing > { + static const bool value = true; +}; + +// This is the default evaluator implementation for products: +// It creates a temporary and call generic_product_impl +template +struct product_evaluator, ProductTag, LhsShape, RhsShape> + : public evaluator::PlainObject> +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef evaluator Base; + enum { + Flags = Base::Flags | EvalBeforeNestingBit + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + +// FIXME shall we handle nested_eval here?, +// if so, then we must take care at removing the call to nested_eval in the specializations (e.g., in permutation_matrix_product, transposition_matrix_product, etc.) +// typedef typename internal::nested_eval::type LhsNested; +// typedef typename internal::nested_eval::type RhsNested; +// typedef typename internal::remove_all::type LhsNestedCleaned; +// typedef typename internal::remove_all::type RhsNestedCleaned; +// +// const LhsNested lhs(xpr.lhs()); +// const RhsNested rhs(xpr.rhs()); +// +// generic_product_impl::evalTo(m_result, lhs, rhs); + + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + +// The following three shortcuts are enabled only if the scalar types match excatly. +// TODO: we could enable them for different scalar types when the product is not vectorized. + +// Dense = Product +template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> +struct Assignment, internal::assign_op, Dense2Dense, + typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct)>::type> +{ + typedef Product SrcXprType; + static EIGEN_STRONG_INLINE + void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + // FIXME shall we handle nested_eval here? + generic_product_impl::evalTo(dst, src.lhs(), src.rhs()); + } +}; + +// Dense += Product +template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> +struct Assignment, internal::add_assign_op, Dense2Dense, + typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct)>::type> +{ + typedef Product SrcXprType; + static EIGEN_STRONG_INLINE + void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &) + { + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + // FIXME shall we handle nested_eval here? + generic_product_impl::addTo(dst, src.lhs(), src.rhs()); + } +}; + +// Dense -= Product +template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> +struct Assignment, internal::sub_assign_op, Dense2Dense, + typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct)>::type> +{ + typedef Product SrcXprType; + static EIGEN_STRONG_INLINE + void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &) + { + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + // FIXME shall we handle nested_eval here? + generic_product_impl::subTo(dst, src.lhs(), src.rhs()); + } +}; + + +// Dense ?= scalar * Product +// TODO we should apply that rule if that's really helpful +// for instance, this is not good for inner products +template< typename DstXprType, typename Lhs, typename Rhs, typename AssignFunc, typename Scalar, typename ScalarBis, typename Plain> +struct Assignment, const CwiseNullaryOp,Plain>, + const Product >, AssignFunc, Dense2Dense> +{ + typedef CwiseBinaryOp, + const CwiseNullaryOp,Plain>, + const Product > SrcXprType; + static EIGEN_STRONG_INLINE + void run(DstXprType &dst, const SrcXprType &src, const AssignFunc& func) + { + call_assignment_no_alias(dst, (src.lhs().functor().m_other * src.rhs().lhs())*src.rhs().rhs(), func); + } +}; + +//---------------------------------------- +// Catch "Dense ?= xpr + Product<>" expression to save one temporary +// FIXME we could probably enable these rules for any product, i.e., not only Dense and DefaultProduct + +template +struct evaluator_assume_aliasing::Scalar>, const OtherXpr, + const Product >, DenseShape > { + static const bool value = true; +}; + +template +struct evaluator_assume_aliasing::Scalar>, const OtherXpr, + const Product >, DenseShape > { + static const bool value = true; +}; + +template +struct assignment_from_xpr_op_product +{ + template + static EIGEN_STRONG_INLINE + void run(DstXprType &dst, const SrcXprType &src, const InitialFunc& /*func*/) + { + call_assignment_no_alias(dst, src.lhs(), Func1()); + call_assignment_no_alias(dst, src.rhs(), Func2()); + } +}; + +#define EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(ASSIGN_OP,BINOP,ASSIGN_OP2) \ + template< typename DstXprType, typename OtherXpr, typename Lhs, typename Rhs, typename DstScalar, typename SrcScalar, typename OtherScalar,typename ProdScalar> \ + struct Assignment, const OtherXpr, \ + const Product >, internal::ASSIGN_OP, Dense2Dense> \ + : assignment_from_xpr_op_product, internal::ASSIGN_OP, internal::ASSIGN_OP2 > \ + {} + +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(assign_op, scalar_sum_op,add_assign_op); +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(add_assign_op,scalar_sum_op,add_assign_op); +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(sub_assign_op,scalar_sum_op,sub_assign_op); + +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(assign_op, scalar_difference_op,sub_assign_op); +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(add_assign_op,scalar_difference_op,sub_assign_op); +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(sub_assign_op,scalar_difference_op,add_assign_op); + +//---------------------------------------- + +template +struct generic_product_impl +{ + template + static EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + dst.coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum(); + } + + template + static EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + dst.coeffRef(0,0) += (lhs.transpose().cwiseProduct(rhs)).sum(); + } + + template + static EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { dst.coeffRef(0,0) -= (lhs.transpose().cwiseProduct(rhs)).sum(); } +}; + + +/*********************************************************************** +* Implementation of outer dense * dense vector product +***********************************************************************/ + +// Column major result +template +void outer_product_selector_run(Dst& dst, const Lhs &lhs, const Rhs &rhs, const Func& func, const false_type&) +{ + evaluator rhsEval(rhs); + typename nested_eval::type actual_lhs(lhs); + // FIXME if cols is large enough, then it might be useful to make sure that lhs is sequentially stored + // FIXME not very good if rhs is real and lhs complex while alpha is real too + const Index cols = dst.cols(); + for (Index j=0; j +void outer_product_selector_run(Dst& dst, const Lhs &lhs, const Rhs &rhs, const Func& func, const true_type&) +{ + evaluator lhsEval(lhs); + typename nested_eval::type actual_rhs(rhs); + // FIXME if rows is large enough, then it might be useful to make sure that rhs is sequentially stored + // FIXME not very good if lhs is real and rhs complex while alpha is real too + const Index rows = dst.rows(); + for (Index i=0; i +struct generic_product_impl +{ + template struct is_row_major : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {}; + typedef typename Product::Scalar Scalar; + + // TODO it would be nice to be able to exploit our *_assign_op functors for that purpose + struct set { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() = src; } }; + struct add { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() += src; } }; + struct sub { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() -= src; } }; + struct adds { + Scalar m_scale; + explicit adds(const Scalar& s) : m_scale(s) {} + template void operator()(const Dst& dst, const Src& src) const { + dst.const_cast_derived() += m_scale * src; + } + }; + + template + static EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + internal::outer_product_selector_run(dst, lhs, rhs, set(), is_row_major()); + } + + template + static EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + internal::outer_product_selector_run(dst, lhs, rhs, add(), is_row_major()); + } + + template + static EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + internal::outer_product_selector_run(dst, lhs, rhs, sub(), is_row_major()); + } + + template + static EIGEN_STRONG_INLINE void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + internal::outer_product_selector_run(dst, lhs, rhs, adds(alpha), is_row_major()); + } + +}; + + +// This base class provides default implementations for evalTo, addTo, subTo, in terms of scaleAndAddTo +template +struct generic_product_impl_base +{ + typedef typename Product::Scalar Scalar; + + template + static EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { dst.setZero(); scaleAndAddTo(dst, lhs, rhs, Scalar(1)); } + + template + static EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { scaleAndAddTo(dst,lhs, rhs, Scalar(1)); } + + template + static EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { scaleAndAddTo(dst, lhs, rhs, Scalar(-1)); } + + template + static EIGEN_STRONG_INLINE void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { Derived::scaleAndAddTo(dst,lhs,rhs,alpha); } + +}; + +template +struct generic_product_impl + : generic_product_impl_base > +{ + typedef typename nested_eval::type LhsNested; + typedef typename nested_eval::type RhsNested; + typedef typename Product::Scalar Scalar; + enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; + typedef typename internal::remove_all::type>::type MatrixType; + + template + static EIGEN_STRONG_INLINE void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + LhsNested actual_lhs(lhs); + RhsNested actual_rhs(rhs); + internal::gemv_dense_selector::HasUsableDirectAccess) + >::run(actual_lhs, actual_rhs, dst, alpha); + } +}; + +template +struct generic_product_impl +{ + typedef typename Product::Scalar Scalar; + + template + static EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + // Same as: dst.noalias() = lhs.lazyProduct(rhs); + // but easier on the compiler side + call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::assign_op()); + } + + template + static EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + // dst.noalias() += lhs.lazyProduct(rhs); + call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::add_assign_op()); + } + + template + static EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + // dst.noalias() -= lhs.lazyProduct(rhs); + call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::sub_assign_op()); + } + +// template +// static inline void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) +// { dst.noalias() += alpha * lhs.lazyProduct(rhs); } +}; + +// This specialization enforces the use of a coefficient-based evaluation strategy +template +struct generic_product_impl + : generic_product_impl {}; + +// Case 2: Evaluate coeff by coeff +// +// This is mostly taken from CoeffBasedProduct.h +// The main difference is that we add an extra argument to the etor_product_*_impl::run() function +// for the inner dimension of the product, because evaluator object do not know their size. + +template +struct etor_product_coeff_impl; + +template +struct etor_product_packet_impl; + +template +struct product_evaluator, ProductTag, DenseShape, DenseShape> + : evaluator_base > +{ + typedef Product XprType; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit product_evaluator(const XprType& xpr) + : m_lhs(xpr.lhs()), + m_rhs(xpr.rhs()), + m_lhsImpl(m_lhs), // FIXME the creation of the evaluator objects should result in a no-op, but check that! + m_rhsImpl(m_rhs), // Moreover, they are only useful for the packet path, so we could completely disable them when not needed, + // or perhaps declare them on the fly on the packet method... We have experiment to check what's best. + m_innerDim(xpr.lhs().cols()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits::MulCost); + EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits::AddCost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); +#if 0 + std::cerr << "LhsOuterStrideBytes= " << LhsOuterStrideBytes << "\n"; + std::cerr << "RhsOuterStrideBytes= " << RhsOuterStrideBytes << "\n"; + std::cerr << "LhsAlignment= " << LhsAlignment << "\n"; + std::cerr << "RhsAlignment= " << RhsAlignment << "\n"; + std::cerr << "CanVectorizeLhs= " << CanVectorizeLhs << "\n"; + std::cerr << "CanVectorizeRhs= " << CanVectorizeRhs << "\n"; + std::cerr << "CanVectorizeInner= " << CanVectorizeInner << "\n"; + std::cerr << "EvalToRowMajor= " << EvalToRowMajor << "\n"; + std::cerr << "Alignment= " << Alignment << "\n"; + std::cerr << "Flags= " << Flags << "\n"; +#endif + } + + // Everything below here is taken from CoeffBasedProduct.h + + typedef typename internal::nested_eval::type LhsNested; + typedef typename internal::nested_eval::type RhsNested; + + typedef typename internal::remove_all::type LhsNestedCleaned; + typedef typename internal::remove_all::type RhsNestedCleaned; + + typedef evaluator LhsEtorType; + typedef evaluator RhsEtorType; + + enum { + RowsAtCompileTime = LhsNestedCleaned::RowsAtCompileTime, + ColsAtCompileTime = RhsNestedCleaned::ColsAtCompileTime, + InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(LhsNestedCleaned::ColsAtCompileTime, RhsNestedCleaned::RowsAtCompileTime), + MaxRowsAtCompileTime = LhsNestedCleaned::MaxRowsAtCompileTime, + MaxColsAtCompileTime = RhsNestedCleaned::MaxColsAtCompileTime + }; + + typedef typename find_best_packet::type LhsVecPacketType; + typedef typename find_best_packet::type RhsVecPacketType; + + enum { + + LhsCoeffReadCost = LhsEtorType::CoeffReadCost, + RhsCoeffReadCost = RhsEtorType::CoeffReadCost, + CoeffReadCost = InnerSize==0 ? NumTraits::ReadCost + : InnerSize == Dynamic ? HugeCost + : InnerSize * (NumTraits::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) + + (InnerSize - 1) * NumTraits::AddCost, + + Unroll = CoeffReadCost <= EIGEN_UNROLLING_LIMIT, + + LhsFlags = LhsEtorType::Flags, + RhsFlags = RhsEtorType::Flags, + + LhsRowMajor = LhsFlags & RowMajorBit, + RhsRowMajor = RhsFlags & RowMajorBit, + + LhsVecPacketSize = unpacket_traits::size, + RhsVecPacketSize = unpacket_traits::size, + + // Here, we don't care about alignment larger than the usable packet size. + LhsAlignment = EIGEN_PLAIN_ENUM_MIN(LhsEtorType::Alignment,LhsVecPacketSize*int(sizeof(typename LhsNestedCleaned::Scalar))), + RhsAlignment = EIGEN_PLAIN_ENUM_MIN(RhsEtorType::Alignment,RhsVecPacketSize*int(sizeof(typename RhsNestedCleaned::Scalar))), + + SameType = is_same::value, + + CanVectorizeRhs = bool(RhsRowMajor) && (RhsFlags & PacketAccessBit) && (ColsAtCompileTime!=1), + CanVectorizeLhs = (!LhsRowMajor) && (LhsFlags & PacketAccessBit) && (RowsAtCompileTime!=1), + + EvalToRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 + : (bool(RhsRowMajor) && !CanVectorizeLhs), + + Flags = ((unsigned int)(LhsFlags | RhsFlags) & HereditaryBits & ~RowMajorBit) + | (EvalToRowMajor ? RowMajorBit : 0) + // TODO enable vectorization for mixed types + | (SameType && (CanVectorizeLhs || CanVectorizeRhs) ? PacketAccessBit : 0) + | (XprType::IsVectorAtCompileTime ? LinearAccessBit : 0), + + LhsOuterStrideBytes = int(LhsNestedCleaned::OuterStrideAtCompileTime) * int(sizeof(typename LhsNestedCleaned::Scalar)), + RhsOuterStrideBytes = int(RhsNestedCleaned::OuterStrideAtCompileTime) * int(sizeof(typename RhsNestedCleaned::Scalar)), + + Alignment = bool(CanVectorizeLhs) ? (LhsOuterStrideBytes<=0 || (int(LhsOuterStrideBytes) % EIGEN_PLAIN_ENUM_MAX(1,LhsAlignment))!=0 ? 0 : LhsAlignment) + : bool(CanVectorizeRhs) ? (RhsOuterStrideBytes<=0 || (int(RhsOuterStrideBytes) % EIGEN_PLAIN_ENUM_MAX(1,RhsAlignment))!=0 ? 0 : RhsAlignment) + : 0, + + /* CanVectorizeInner deserves special explanation. It does not affect the product flags. It is not used outside + * of Product. If the Product itself is not a packet-access expression, there is still a chance that the inner + * loop of the product might be vectorized. This is the meaning of CanVectorizeInner. Since it doesn't affect + * the Flags, it is safe to make this value depend on ActualPacketAccessBit, that doesn't affect the ABI. + */ + CanVectorizeInner = SameType + && LhsRowMajor + && (!RhsRowMajor) + && (LhsFlags & RhsFlags & ActualPacketAccessBit) + && (InnerSize % packet_traits::size == 0) + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index row, Index col) const + { + return (m_lhs.row(row).transpose().cwiseProduct( m_rhs.col(col) )).sum(); + } + + /* Allow index-based non-packet access. It is impossible though to allow index-based packed access, + * which is why we don't set the LinearAccessBit. + * TODO: this seems possible when the result is a vector + */ + EIGEN_DEVICE_FUNC const CoeffReturnType coeff(Index index) const + { + const Index row = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? 0 : index; + const Index col = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? index : 0; + return (m_lhs.row(row).transpose().cwiseProduct( m_rhs.col(col) )).sum(); + } + + template + const PacketType packet(Index row, Index col) const + { + PacketType res; + typedef etor_product_packet_impl PacketImpl; + PacketImpl::run(row, col, m_lhsImpl, m_rhsImpl, m_innerDim, res); + return res; + } + + template + const PacketType packet(Index index) const + { + const Index row = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? 0 : index; + const Index col = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? index : 0; + return packet(row,col); + } + +protected: + typename internal::add_const_on_value_type::type m_lhs; + typename internal::add_const_on_value_type::type m_rhs; + + LhsEtorType m_lhsImpl; + RhsEtorType m_rhsImpl; + + // TODO: Get rid of m_innerDim if known at compile time + Index m_innerDim; +}; + +template +struct product_evaluator, LazyCoeffBasedProductMode, DenseShape, DenseShape> + : product_evaluator, CoeffBasedProductMode, DenseShape, DenseShape> +{ + typedef Product XprType; + typedef Product BaseProduct; + typedef product_evaluator Base; + enum { + Flags = Base::Flags | EvalBeforeNestingBit + }; + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) + : Base(BaseProduct(xpr.lhs(),xpr.rhs())) + {} +}; + +/**************************************** +*** Coeff based product, Packet path *** +****************************************/ + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet &res) + { + etor_product_packet_impl::run(row, col, lhs, rhs, innerDim, res); + res = pmadd(pset1(lhs.coeff(row, Index(UnrollingIndex-1))), rhs.template packet(Index(UnrollingIndex-1), col), res); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet &res) + { + etor_product_packet_impl::run(row, col, lhs, rhs, innerDim, res); + res = pmadd(lhs.template packet(row, Index(UnrollingIndex-1)), pset1(rhs.coeff(Index(UnrollingIndex-1), col)), res); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, Packet &res) + { + res = pmul(pset1(lhs.coeff(row, Index(0))),rhs.template packet(Index(0), col)); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, Packet &res) + { + res = pmul(lhs.template packet(row, Index(0)), pset1(rhs.coeff(Index(0), col))); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Index /*innerDim*/, Packet &res) + { + res = pset1(typename unpacket_traits::type(0)); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Index /*innerDim*/, Packet &res) + { + res = pset1(typename unpacket_traits::type(0)); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet& res) + { + res = pset1(typename unpacket_traits::type(0)); + for(Index i = 0; i < innerDim; ++i) + res = pmadd(pset1(lhs.coeff(row, i)), rhs.template packet(i, col), res); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet& res) + { + res = pset1(typename unpacket_traits::type(0)); + for(Index i = 0; i < innerDim; ++i) + res = pmadd(lhs.template packet(row, i), pset1(rhs.coeff(i, col)), res); + } +}; + + +/*************************************************************************** +* Triangular products +***************************************************************************/ +template +struct triangular_product_impl; + +template +struct generic_product_impl + : generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + triangular_product_impl + ::run(dst, lhs.nestedExpression(), rhs, alpha); + } +}; + +template +struct generic_product_impl +: generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + triangular_product_impl::run(dst, lhs, rhs.nestedExpression(), alpha); + } +}; + + +/*************************************************************************** +* SelfAdjoint products +***************************************************************************/ +template +struct selfadjoint_product_impl; + +template +struct generic_product_impl + : generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + selfadjoint_product_impl::run(dst, lhs.nestedExpression(), rhs, alpha); + } +}; + +template +struct generic_product_impl +: generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + selfadjoint_product_impl::run(dst, lhs, rhs.nestedExpression(), alpha); + } +}; + + +/*************************************************************************** +* Diagonal products +***************************************************************************/ + +template +struct diagonal_product_evaluator_base + : evaluator_base +{ + typedef typename ScalarBinaryOpTraits::ReturnType Scalar; +public: + enum { + CoeffReadCost = NumTraits::MulCost + evaluator::CoeffReadCost + evaluator::CoeffReadCost, + + MatrixFlags = evaluator::Flags, + DiagFlags = evaluator::Flags, + _StorageOrder = MatrixFlags & RowMajorBit ? RowMajor : ColMajor, + _ScalarAccessOnDiag = !((int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheLeft) + ||(int(_StorageOrder) == RowMajor && int(ProductOrder) == OnTheRight)), + _SameTypes = is_same::value, + // FIXME currently we need same types, but in the future the next rule should be the one + //_Vectorizable = bool(int(MatrixFlags)&PacketAccessBit) && ((!_PacketOnDiag) || (_SameTypes && bool(int(DiagFlags)&PacketAccessBit))), + _Vectorizable = bool(int(MatrixFlags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagFlags)&PacketAccessBit))), + _LinearAccessMask = (MatrixType::RowsAtCompileTime==1 || MatrixType::ColsAtCompileTime==1) ? LinearAccessBit : 0, + Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixFlags)) | (_Vectorizable ? PacketAccessBit : 0), + Alignment = evaluator::Alignment, + + AsScalarProduct = (DiagonalType::SizeAtCompileTime==1) + || (DiagonalType::SizeAtCompileTime==Dynamic && MatrixType::RowsAtCompileTime==1 && ProductOrder==OnTheLeft) + || (DiagonalType::SizeAtCompileTime==Dynamic && MatrixType::ColsAtCompileTime==1 && ProductOrder==OnTheRight) + }; + + diagonal_product_evaluator_base(const MatrixType &mat, const DiagonalType &diag) + : m_diagImpl(diag), m_matImpl(mat) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits::MulCost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const + { + if(AsScalarProduct) + return m_diagImpl.coeff(0) * m_matImpl.coeff(idx); + else + return m_diagImpl.coeff(idx) * m_matImpl.coeff(idx); + } + +protected: + template + EIGEN_STRONG_INLINE PacketType packet_impl(Index row, Index col, Index id, internal::true_type) const + { + return internal::pmul(m_matImpl.template packet(row, col), + internal::pset1(m_diagImpl.coeff(id))); + } + + template + EIGEN_STRONG_INLINE PacketType packet_impl(Index row, Index col, Index id, internal::false_type) const + { + enum { + InnerSize = (MatrixType::Flags & RowMajorBit) ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime, + DiagonalPacketLoadMode = EIGEN_PLAIN_ENUM_MIN(LoadMode,((InnerSize%16) == 0) ? int(Aligned16) : int(evaluator::Alignment)) // FIXME hardcoded 16!! + }; + return internal::pmul(m_matImpl.template packet(row, col), + m_diagImpl.template packet(id)); + } + + evaluator m_diagImpl; + evaluator m_matImpl; +}; + +// diagonal * dense +template +struct product_evaluator, ProductTag, DiagonalShape, DenseShape> + : diagonal_product_evaluator_base, OnTheLeft> +{ + typedef diagonal_product_evaluator_base, OnTheLeft> Base; + using Base::m_diagImpl; + using Base::m_matImpl; + using Base::coeff; + typedef typename Base::Scalar Scalar; + + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + + enum { + StorageOrder = int(Rhs::Flags) & RowMajorBit ? RowMajor : ColMajor + }; + + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) + : Base(xpr.rhs(), xpr.lhs().diagonal()) + { + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const + { + return m_diagImpl.coeff(row) * m_matImpl.coeff(row, col); + } + +#ifndef __CUDACC__ + template + EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const + { + // FIXME: NVCC used to complain about the template keyword, but we have to check whether this is still the case. + // See also similar calls below. + return this->template packet_impl(row,col, row, + typename internal::conditional::type()); + } + + template + EIGEN_STRONG_INLINE PacketType packet(Index idx) const + { + return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); + } +#endif +}; + +// dense * diagonal +template +struct product_evaluator, ProductTag, DenseShape, DiagonalShape> + : diagonal_product_evaluator_base, OnTheRight> +{ + typedef diagonal_product_evaluator_base, OnTheRight> Base; + using Base::m_diagImpl; + using Base::m_matImpl; + using Base::coeff; + typedef typename Base::Scalar Scalar; + + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + + enum { StorageOrder = int(Lhs::Flags) & RowMajorBit ? RowMajor : ColMajor }; + + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) + : Base(xpr.lhs(), xpr.rhs().diagonal()) + { + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const + { + return m_matImpl.coeff(row, col) * m_diagImpl.coeff(col); + } + +#ifndef __CUDACC__ + template + EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const + { + return this->template packet_impl(row,col, col, + typename internal::conditional::type()); + } + + template + EIGEN_STRONG_INLINE PacketType packet(Index idx) const + { + return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); + } +#endif +}; + +/*************************************************************************** +* Products with permutation matrices +***************************************************************************/ + +/** \internal + * \class permutation_matrix_product + * Internal helper class implementing the product between a permutation matrix and a matrix. + * This class is specialized for DenseShape below and for SparseShape in SparseCore/SparsePermutation.h + */ +template +struct permutation_matrix_product; + +template +struct permutation_matrix_product +{ + typedef typename nested_eval::type MatrixType; + typedef typename remove_all::type MatrixTypeCleaned; + + template + static inline void run(Dest& dst, const PermutationType& perm, const ExpressionType& xpr) + { + MatrixType mat(xpr); + const Index n = Side==OnTheLeft ? mat.rows() : mat.cols(); + // FIXME we need an is_same for expression that is not sensitive to constness. For instance + // is_same_xpr, Block >::value should be true. + //if(is_same::value && extract_data(dst) == extract_data(mat)) + if(is_same_dense(dst, mat)) + { + // apply the permutation inplace + Matrix mask(perm.size()); + mask.fill(false); + Index r = 0; + while(r < perm.size()) + { + // search for the next seed + while(r=perm.size()) + break; + // we got one, let's follow it until we are back to the seed + Index k0 = r++; + Index kPrev = k0; + mask.coeffRef(k0) = true; + for(Index k=perm.indices().coeff(k0); k!=k0; k=perm.indices().coeff(k)) + { + Block(dst, k) + .swap(Block + (dst,((Side==OnTheLeft) ^ Transposed) ? k0 : kPrev)); + + mask.coeffRef(k) = true; + kPrev = k; + } + } + } + else + { + for(Index i = 0; i < n; ++i) + { + Block + (dst, ((Side==OnTheLeft) ^ Transposed) ? perm.indices().coeff(i) : i) + + = + + Block + (mat, ((Side==OnTheRight) ^ Transposed) ? perm.indices().coeff(i) : i); + } + } + } +}; + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + permutation_matrix_product::run(dst, lhs, rhs); + } +}; + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + permutation_matrix_product::run(dst, rhs, lhs); + } +}; + +template +struct generic_product_impl, Rhs, PermutationShape, MatrixShape, ProductTag> +{ + template + static void evalTo(Dest& dst, const Inverse& lhs, const Rhs& rhs) + { + permutation_matrix_product::run(dst, lhs.nestedExpression(), rhs); + } +}; + +template +struct generic_product_impl, MatrixShape, PermutationShape, ProductTag> +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Inverse& rhs) + { + permutation_matrix_product::run(dst, rhs.nestedExpression(), lhs); + } +}; + + +/*************************************************************************** +* Products with transpositions matrices +***************************************************************************/ + +// FIXME could we unify Transpositions and Permutation into a single "shape"?? + +/** \internal + * \class transposition_matrix_product + * Internal helper class implementing the product between a permutation matrix and a matrix. + */ +template +struct transposition_matrix_product +{ + typedef typename nested_eval::type MatrixType; + typedef typename remove_all::type MatrixTypeCleaned; + + template + static inline void run(Dest& dst, const TranspositionType& tr, const ExpressionType& xpr) + { + MatrixType mat(xpr); + typedef typename TranspositionType::StorageIndex StorageIndex; + const Index size = tr.size(); + StorageIndex j = 0; + + if(!is_same_dense(dst,mat)) + dst = mat; + + for(Index k=(Transposed?size-1:0) ; Transposed?k>=0:k +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + transposition_matrix_product::run(dst, lhs, rhs); + } +}; + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + transposition_matrix_product::run(dst, rhs, lhs); + } +}; + + +template +struct generic_product_impl, Rhs, TranspositionsShape, MatrixShape, ProductTag> +{ + template + static void evalTo(Dest& dst, const Transpose& lhs, const Rhs& rhs) + { + transposition_matrix_product::run(dst, lhs.nestedExpression(), rhs); + } +}; + +template +struct generic_product_impl, MatrixShape, TranspositionsShape, ProductTag> +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Transpose& rhs) + { + transposition_matrix_product::run(dst, rhs.nestedExpression(), lhs); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_PRODUCT_EVALUATORS_H diff --git a/splinter/src/Core/Random.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Random.h similarity index 68% rename from splinter/src/Core/Random.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/Random.h index 480fea408d..6faf789c76 100644 --- a/splinter/src/Core/Random.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Random.h @@ -16,8 +16,7 @@ namespace internal { template struct scalar_random_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_random_op) - template - inline const Scalar operator() (Index, Index = 0) const { return random(); } + inline const Scalar operator() () const { return random(); } }; template @@ -28,12 +27,18 @@ struct functor_traits > /** \returns a random matrix expression * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * + * \not_reentrant + * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, * it is redundant to pass \a rows and \a cols as arguments, so Random() should be used * instead. + * * * Example: \include MatrixBase_random_int_int.cpp * Output: \verbinclude MatrixBase_random_int_int.out @@ -41,22 +46,28 @@ struct functor_traits > * This expression has the "evaluate before nesting" flag so that it will be evaluated into * a temporary matrix whenever it is nested in a larger expression. This prevents unexpected * behavior with expressions involving random matrices. + * + * See DenseBase::NullaryExpr(Index, const CustomNullaryOp&) for an example using C++11 random generators. * - * \sa MatrixBase::setRandom(), MatrixBase::Random(Index), MatrixBase::Random() + * \sa DenseBase::setRandom(), DenseBase::Random(Index), DenseBase::Random() */ template -inline const CwiseNullaryOp::Scalar>, Derived> +inline const typename DenseBase::RandomReturnType DenseBase::Random(Index rows, Index cols) { return NullaryExpr(rows, cols, internal::scalar_random_op()); } /** \returns a random vector expression + * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. * * The parameter \a size is the size of the returned vector. * Must be compatible with this MatrixBase type. * * \only_for_vectors + * \not_reentrant * * This variant is meant to be used for dynamic-size vector types. For fixed-size types, * it is redundant to pass \a size as argument, so Random() should be used @@ -69,10 +80,10 @@ DenseBase::Random(Index rows, Index cols) * a temporary vector whenever it is nested in a larger expression. This prevents unexpected * behavior with expressions involving random matrices. * - * \sa MatrixBase::setRandom(), MatrixBase::Random(Index,Index), MatrixBase::Random() + * \sa DenseBase::setRandom(), DenseBase::Random(Index,Index), DenseBase::Random() */ template -inline const CwiseNullaryOp::Scalar>, Derived> +inline const typename DenseBase::RandomReturnType DenseBase::Random(Index size) { return NullaryExpr(size, internal::scalar_random_op()); @@ -80,6 +91,9 @@ DenseBase::Random(Index size) /** \returns a fixed-size random matrix or vector expression * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you * need to use the variants taking size arguments. * @@ -89,11 +103,13 @@ DenseBase::Random(Index size) * This expression has the "evaluate before nesting" flag so that it will be evaluated into * a temporary matrix whenever it is nested in a larger expression. This prevents unexpected * behavior with expressions involving random matrices. + * + * \not_reentrant * - * \sa MatrixBase::setRandom(), MatrixBase::Random(Index,Index), MatrixBase::Random(Index) + * \sa DenseBase::setRandom(), DenseBase::Random(Index,Index), DenseBase::Random(Index) */ template -inline const CwiseNullaryOp::Scalar>, Derived> +inline const typename DenseBase::RandomReturnType DenseBase::Random() { return NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_random_op()); @@ -101,6 +117,11 @@ DenseBase::Random() /** Sets all coefficients in this expression to random values. * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * + * \not_reentrant + * * Example: \include MatrixBase_setRandom.cpp * Output: \verbinclude MatrixBase_setRandom.out * @@ -114,12 +135,16 @@ inline Derived& DenseBase::setRandom() /** Resizes to the given \a newSize, and sets all coefficients in this expression to random values. * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * * \only_for_vectors + * \not_reentrant * * Example: \include Matrix_setRandom_int.cpp * Output: \verbinclude Matrix_setRandom_int.out * - * \sa MatrixBase::setRandom(), setRandom(Index,Index), class CwiseNullaryOp, MatrixBase::Random() + * \sa DenseBase::setRandom(), setRandom(Index,Index), class CwiseNullaryOp, DenseBase::Random() */ template EIGEN_STRONG_INLINE Derived& @@ -131,19 +156,24 @@ PlainObjectBase::setRandom(Index newSize) /** Resizes to the given size, and sets all coefficients in this expression to random values. * - * \param nbRows the new number of rows - * \param nbCols the new number of columns + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * + * \not_reentrant + * + * \param rows the new number of rows + * \param cols the new number of columns * * Example: \include Matrix_setRandom_int_int.cpp * Output: \verbinclude Matrix_setRandom_int_int.out * - * \sa MatrixBase::setRandom(), setRandom(Index), class CwiseNullaryOp, MatrixBase::Random() + * \sa DenseBase::setRandom(), setRandom(Index), class CwiseNullaryOp, DenseBase::Random() */ template EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setRandom(Index nbRows, Index nbCols) +PlainObjectBase::setRandom(Index rows, Index cols) { - resize(nbRows, nbCols); + resize(rows, cols); return setRandom(); } diff --git a/splinter/src/Core/Redux.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Redux.h similarity index 60% rename from splinter/src/Core/Redux.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/Redux.h index 9b8662a6f9..760e9f8615 100644 --- a/splinter/src/Core/Redux.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Redux.h @@ -27,8 +27,9 @@ template struct redux_traits { public: + typedef typename find_best_packet::type PacketType; enum { - PacketSize = packet_traits::size, + PacketSize = unpacket_traits::size, InnerMaxSize = int(Derived::IsRowMajor) ? Derived::MaxColsAtCompileTime : Derived::MaxRowsAtCompileTime @@ -37,8 +38,8 @@ struct redux_traits enum { MightVectorize = (int(Derived::Flags)&ActualPacketAccessBit) && (functor_traits::PacketAccess), - MayLinearVectorize = MightVectorize && (int(Derived::Flags)&LinearAccessBit), - MaySliceVectorize = MightVectorize && int(InnerMaxSize)>=3*PacketSize + MayLinearVectorize = bool(MightVectorize) && (int(Derived::Flags)&LinearAccessBit), + MaySliceVectorize = bool(MightVectorize) && int(InnerMaxSize)>=3*PacketSize }; public: @@ -50,21 +51,34 @@ struct redux_traits public: enum { - Cost = ( Derived::SizeAtCompileTime == Dynamic - || Derived::CoeffReadCost == Dynamic - || (Derived::SizeAtCompileTime!=1 && functor_traits::Cost == Dynamic) - ) ? Dynamic - : Derived::SizeAtCompileTime * Derived::CoeffReadCost - + (Derived::SizeAtCompileTime-1) * functor_traits::Cost, + Cost = Derived::SizeAtCompileTime == Dynamic ? HugeCost + : Derived::SizeAtCompileTime * Derived::CoeffReadCost + (Derived::SizeAtCompileTime-1) * functor_traits::Cost, UnrollingLimit = EIGEN_UNROLLING_LIMIT * (int(Traversal) == int(DefaultTraversal) ? 1 : int(PacketSize)) }; public: enum { - Unrolling = Cost != Dynamic && Cost <= UnrollingLimit - ? CompleteUnrolling - : NoUnrolling + Unrolling = Cost <= UnrollingLimit ? CompleteUnrolling : NoUnrolling }; + +#ifdef EIGEN_DEBUG_ASSIGN + static void debug() + { + std::cerr << "Xpr: " << typeid(typename Derived::XprType).name() << std::endl; + std::cerr.setf(std::ios::hex, std::ios::basefield); + EIGEN_DEBUG_VAR(Derived::Flags) + std::cerr.unsetf(std::ios::hex); + EIGEN_DEBUG_VAR(InnerMaxSize) + EIGEN_DEBUG_VAR(PacketSize) + EIGEN_DEBUG_VAR(MightVectorize) + EIGEN_DEBUG_VAR(MayLinearVectorize) + EIGEN_DEBUG_VAR(MaySliceVectorize) + EIGEN_DEBUG_VAR(Traversal) + EIGEN_DEBUG_VAR(UnrollingLimit) + EIGEN_DEBUG_VAR(Unrolling) + std::cerr << std::endl; + } +#endif }; /*************************************************************************** @@ -82,6 +96,7 @@ struct redux_novec_unroller typedef typename Derived::Scalar Scalar; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) { return func(redux_novec_unroller::run(mat,func), @@ -99,6 +114,7 @@ struct redux_novec_unroller typedef typename Derived::Scalar Scalar; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func&) { return mat.coeffByOuterInner(outer, inner); @@ -112,6 +128,7 @@ template struct redux_novec_unroller { typedef typename Derived::Scalar Scalar; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived&, const Func&) { return Scalar(); } }; @@ -121,12 +138,12 @@ template struct redux_vec_unroller { enum { - PacketSize = packet_traits::size, + PacketSize = redux_traits::PacketSize, HalfLength = Length/2 }; typedef typename Derived::Scalar Scalar; - typedef typename packet_traits::type PacketScalar; + typedef typename redux_traits::PacketType PacketScalar; static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func& func) { @@ -140,18 +157,18 @@ template struct redux_vec_unroller { enum { - index = Start * packet_traits::size, + index = Start * redux_traits::PacketSize, outer = index / int(Derived::InnerSizeAtCompileTime), inner = index % int(Derived::InnerSizeAtCompileTime), - alignment = (Derived::Flags & AlignedBit) ? Aligned : Unaligned + alignment = Derived::Alignment }; typedef typename Derived::Scalar Scalar; - typedef typename packet_traits::type PacketScalar; + typedef typename redux_traits::PacketType PacketScalar; static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func&) { - return mat.template packetByOuterInner(outer, inner); + return mat.template packetByOuterInner(outer, inner); } }; @@ -169,8 +186,8 @@ template struct redux_impl { typedef typename Derived::Scalar Scalar; - typedef typename Derived::Index Index; - static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func) + EIGEN_DEVICE_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; @@ -193,19 +210,19 @@ template struct redux_impl { typedef typename Derived::Scalar Scalar; - typedef typename packet_traits::type PacketScalar; - typedef typename Derived::Index Index; + typedef typename redux_traits::PacketType PacketScalar; - static Scalar run(const Derived& mat, const Func& func) + static Scalar run(const Derived &mat, const Func& func) { const Index size = mat.size(); - eigen_assert(size && "you are using an empty matrix"); - const Index packetSize = packet_traits::size; - const Index alignedStart = internal::first_aligned(mat); + + const Index packetSize = redux_traits::PacketSize; + const int packetAlignment = unpacket_traits::alignment; enum { - alignment = bool(Derived::Flags & DirectAccessBit) || bool(Derived::Flags & AlignedBit) - ? Aligned : Unaligned + alignment0 = (bool(Derived::Flags & DirectAccessBit) && bool(packet_traits::AlignedOnScalar)) ? int(packetAlignment) : int(Unaligned), + alignment = EIGEN_PLAIN_ENUM_MAX(alignment0, Derived::Alignment) }; + const Index alignedStart = internal::first_default_aligned(mat.nestedExpression()); const Index alignedSize2 = ((size-alignedStart)/(2*packetSize))*(2*packetSize); const Index alignedSize = ((size-alignedStart)/(packetSize))*(packetSize); const Index alignedEnd2 = alignedStart + alignedSize2; @@ -213,19 +230,19 @@ struct redux_impl Scalar res; if(alignedSize) { - PacketScalar packet_res0 = mat.template packet(alignedStart); + 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); + 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, 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)); + packet_res0 = func.packetOp(packet_res0, mat.template packet(alignedEnd2)); } res = func.predux(packet_res0); @@ -252,25 +269,24 @@ template struct redux_impl { typedef typename Derived::Scalar Scalar; - typedef typename packet_traits::type PacketScalar; - typedef typename Derived::Index Index; + typedef typename redux_traits::PacketType PacketType; - static Scalar run(const Derived& mat, const Func& func) + EIGEN_DEVICE_FUNC static Scalar run(const Derived &mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); const Index innerSize = mat.innerSize(); const Index outerSize = mat.outerSize(); enum { - packetSize = packet_traits::size + packetSize = redux_traits::PacketSize }; const Index packetedInnerSize = ((innerSize)/packetSize)*packetSize; Scalar res; if(packetedInnerSize) { - PacketScalar packet_res = mat.template packet(0,0); + PacketType packet_res = mat.template packet(0,0); for(Index j=0; j(j,i)); + packet_res = func.packetOp(packet_res, mat.template packetByOuterInner(j,i)); res = func.predux(packet_res); for(Index j=0; j struct redux_impl { typedef typename Derived::Scalar Scalar; - typedef typename packet_traits::type PacketScalar; + + typedef typename redux_traits::PacketType PacketScalar; enum { - PacketSize = packet_traits::size, + PacketSize = redux_traits::PacketSize, Size = Derived::SizeAtCompileTime, VectorizedSize = (Size / PacketSize) * PacketSize }; - static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func) + EIGEN_DEVICE_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)); - if (VectorizedSize != Size) - res = func(res,redux_novec_unroller::run(mat,func)); - return res; + if (VectorizedSize > 0) { + Scalar res = func.predux(redux_vec_unroller::run(mat,func)); + if (VectorizedSize != Size) + res = func(res,redux_novec_unroller::run(mat,func)); + return res; + } + else { + return redux_novec_unroller::run(mat,func); + } } }; +// evaluator adaptor +template +class redux_evaluator +{ +public: + typedef _XprType XprType; + EIGEN_DEVICE_FUNC explicit redux_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename XprType::PacketScalar PacketScalar; + typedef typename XprType::PacketReturnType PacketReturnType; + + enum { + MaxRowsAtCompileTime = XprType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = XprType::MaxColsAtCompileTime, + // TODO we should not remove DirectAccessBit and rather find an elegant way to query the alignment offset at runtime from the evaluator + Flags = evaluator::Flags & ~DirectAccessBit, + IsRowMajor = XprType::IsRowMajor, + SizeAtCompileTime = XprType::SizeAtCompileTime, + InnerSizeAtCompileTime = XprType::InnerSizeAtCompileTime, + CoeffReadCost = evaluator::CoeffReadCost, + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC Index rows() const { return m_xpr.rows(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_xpr.cols(); } + EIGEN_DEVICE_FUNC Index size() const { return m_xpr.size(); } + EIGEN_DEVICE_FUNC Index innerSize() const { return m_xpr.innerSize(); } + EIGEN_DEVICE_FUNC Index outerSize() const { return m_xpr.outerSize(); } + + EIGEN_DEVICE_FUNC + CoeffReturnType coeff(Index row, Index col) const + { return m_evaluator.coeff(row, col); } + + EIGEN_DEVICE_FUNC + CoeffReturnType coeff(Index index) const + { return m_evaluator.coeff(index); } + + template + PacketType packet(Index row, Index col) const + { return m_evaluator.template packet(row, col); } + + template + PacketType packet(Index index) const + { return m_evaluator.template packet(index); } + + EIGEN_DEVICE_FUNC + CoeffReturnType coeffByOuterInner(Index outer, Index inner) const + { return m_evaluator.coeff(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); } + + template + PacketType packetByOuterInner(Index outer, Index inner) const + { return m_evaluator.template packet(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); } + + const XprType & nestedExpression() const { return m_xpr; } + +protected: + internal::evaluator m_evaluator; + const XprType &m_xpr; +}; + } // end namespace internal /*************************************************************************** @@ -317,18 +401,21 @@ struct redux_impl /** \returns the result of a full redux operation on the whole matrix or vector using \a func * * The template parameter \a BinaryOp is the type of the functor \a func which must be - * an associative operator. Both current STL and TR1 functor styles are handled. + * an associative operator. Both current C++98 and C++11 functor styles are handled. * * \sa DenseBase::sum(), DenseBase::minCoeff(), DenseBase::maxCoeff(), MatrixBase::colwise(), MatrixBase::rowwise() */ template template -EIGEN_STRONG_INLINE typename internal::result_of::Scalar)>::type +EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::redux(const Func& func) const { - typedef typename internal::remove_all::type ThisNested; - return internal::redux_impl - ::run(derived(), func); + eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix"); + + typedef typename internal::redux_evaluator ThisEvaluator; + ThisEvaluator thisEval(derived()); + + return internal::redux_impl::run(thisEval, func); } /** \returns the minimum of all coefficients of \c *this. @@ -338,7 +425,7 @@ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::minCoeff() const { - return this->redux(Eigen::internal::scalar_min_op()); + return derived().redux(Eigen::internal::scalar_min_op()); } /** \returns the maximum of all coefficients of \c *this. @@ -348,10 +435,12 @@ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::maxCoeff() const { - return this->redux(Eigen::internal::scalar_max_op()); + return derived().redux(Eigen::internal::scalar_max_op()); } -/** \returns the sum of all coefficients of *this +/** \returns the sum of all coefficients of \c *this + * + * If \c *this is empty, then the value 0 is returned. * * \sa trace(), prod(), mean() */ @@ -361,7 +450,7 @@ DenseBase::sum() const { if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) return Scalar(0); - return this->redux(Eigen::internal::scalar_sum_op()); + return derived().redux(Eigen::internal::scalar_sum_op()); } /** \returns the mean of all coefficients of *this @@ -372,7 +461,14 @@ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::mean() const { - return Scalar(this->redux(Eigen::internal::scalar_sum_op())) / Scalar(this->size()); +#ifdef __INTEL_COMPILER + #pragma warning push + #pragma warning ( disable : 2259 ) +#endif + return Scalar(derived().redux(Eigen::internal::scalar_sum_op())) / Scalar(this->size()); +#ifdef __INTEL_COMPILER + #pragma warning pop +#endif } /** \returns the product of all coefficients of *this @@ -388,7 +484,7 @@ DenseBase::prod() const { if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) return Scalar(1); - return this->redux(Eigen::internal::scalar_product_op()); + return derived().redux(Eigen::internal::scalar_product_op()); } /** \returns the trace of \c *this, i.e. the sum of the coefficients on the main diagonal. diff --git a/splinter/src/Core/Ref.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Ref.h similarity index 69% rename from splinter/src/Core/Ref.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/Ref.h index 7a3becaf88..9c6e3c5d9b 100644 --- a/splinter/src/Core/Ref.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Ref.h @@ -12,79 +12,6 @@ namespace Eigen { -template class RefBase; -template,OuterStride<> >::type > class Ref; - -/** \class Ref - * \ingroup Core_Module - * - * \brief A matrix or vector expression mapping an existing expressions - * - * \tparam PlainObjectType the equivalent matrix type of the mapped data - * \tparam Options specifies whether the pointer is \c #Aligned, or \c #Unaligned. - * The default is \c #Unaligned. - * \tparam StrideType optionally specifies strides. By default, Ref implies a contiguous storage along the inner dimension (inner stride==1), - * but accept a variable outer stride (leading dimension). - * This can be overridden by specifying strides. - * The type passed here must be a specialization of the Stride template, see examples below. - * - * This class permits to write non template functions taking Eigen's object as parameters while limiting the number of copies. - * A Ref<> object can represent either a const expression or a l-value: - * \code - * // in-out argument: - * void foo1(Ref x); - * - * // read-only const argument: - * void foo2(const Ref& x); - * \endcode - * - * In the in-out case, the input argument must satisfies the constraints of the actual Ref<> type, otherwise a compilation issue will be triggered. - * By default, a Ref can reference any dense vector expression of float having a contiguous memory layout. - * Likewise, a Ref can reference any column major dense matrix expression of float whose column's elements are contiguously stored with - * the possibility to have a constant space inbetween each column, i.e.: the inner stride mmust be equal to 1, but the outer-stride (or leading dimension), - * can be greater than the number of rows. - * - * In the const case, if the input expression does not match the above requirement, then it is evaluated into a temporary before being passed to the function. - * Here are some examples: - * \code - * MatrixXf A; - * VectorXf a; - * foo1(a.head()); // OK - * foo1(A.col()); // OK - * foo1(A.row()); // compilation error because here innerstride!=1 - * foo2(A.row()); // The row is copied into a contiguous temporary - * foo2(2*a); // The expression is evaluated into a temporary - * foo2(A.col().segment(2,4)); // No temporary - * \endcode - * - * The range of inputs that can be referenced without temporary can be enlarged using the last two template parameter. - * Here is an example accepting an innerstride!=1: - * \code - * // in-out argument: - * void foo3(Ref > x); - * foo3(A.row()); // OK - * \endcode - * The downside here is that the function foo3 might be significantly slower than foo1 because it won't be able to exploit vectorization, and will involved more - * expensive address computations even if the input is contiguously stored in memory. To overcome this issue, one might propose to overloads internally calling a - * template function, e.g.: - * \code - * // in the .h: - * void foo(const Ref& A); - * void foo(const Ref >& A); - * - * // in the .cpp: - * template void foo_impl(const TypeOfA& A) { - * ... // crazy code goes here - * } - * void foo(const Ref& A) { foo_impl(A); } - * void foo(const Ref >& A) { foo_impl(A); } - * \endcode - * - * - * \sa PlainObjectBase::Map(), \ref TopicStorageOrders - */ - namespace internal { template @@ -95,7 +22,8 @@ struct traits > typedef _StrideType StrideType; enum { Options = _Options, - Flags = traits >::Flags | NestByRefBit + Flags = traits >::Flags | NestByRefBit, + Alignment = traits >::Alignment }; template struct match { @@ -107,7 +35,13 @@ struct traits > || (int(StrideType::InnerStrideAtCompileTime)==0 && int(Derived::InnerStrideAtCompileTime)==1), OuterStrideMatch = Derived::IsVectorAtCompileTime || int(StrideType::OuterStrideAtCompileTime)==int(Dynamic) || int(StrideType::OuterStrideAtCompileTime)==int(Derived::OuterStrideAtCompileTime), - AlignmentMatch = (_Options!=Aligned) || ((PlainObjectType::Flags&AlignedBit)==0) || ((traits::Flags&AlignedBit)==AlignedBit), + // NOTE, this indirection of evaluator::Alignment is needed + // to workaround a very strange bug in MSVC related to the instantiation + // of has_*ary_operator in evaluator. + // This line is surprisingly very sensitive. For instance, simply adding parenthesis + // as "DerivedAlignment = (int(evaluator::Alignment))," will make MSVC fail... + DerivedAlignment = int(evaluator::Alignment), + AlignmentMatch = (int(traits::Alignment)==int(Unaligned)) || (DerivedAlignment >= int(Alignment)), // FIXME the first condition is not very clear, it should be replaced by the required alignment ScalarTypeMatch = internal::is_same::value, MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch && ScalarTypeMatch }; @@ -132,12 +66,12 @@ template class RefBase typedef MapBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(RefBase) - inline Index innerStride() const + EIGEN_DEVICE_FUNC inline Index innerStride() const { return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; } - inline Index outerStride() const + EIGEN_DEVICE_FUNC inline Index outerStride() const { return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer() : IsVectorAtCompileTime ? this->size() @@ -145,7 +79,7 @@ template class RefBase : this->rows(); } - RefBase() + EIGEN_DEVICE_FUNC RefBase() : Base(0,RowsAtCompileTime==Dynamic?0:RowsAtCompileTime,ColsAtCompileTime==Dynamic?0:ColsAtCompileTime), // Stride<> does not allow default ctor for Dynamic strides, so let' initialize it with dummy values: m_stride(StrideType::OuterStrideAtCompileTime==Dynamic?0:StrideType::OuterStrideAtCompileTime, @@ -159,8 +93,10 @@ template class RefBase typedef Stride StrideBase; template - void construct(Expression& expr) + EIGEN_DEVICE_FUNC void construct(Expression& expr) { + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(PlainObjectType,Expression); + if(PlainObjectType::RowsAtCompileTime==1) { eigen_assert(expr.rows()==1 || expr.cols()==1); @@ -184,15 +120,83 @@ template class RefBase StrideBase m_stride; }; - +/** \class Ref + * \ingroup Core_Module + * + * \brief A matrix or vector expression mapping an existing expression + * + * \tparam PlainObjectType the equivalent matrix type of the mapped data + * \tparam Options specifies the pointer alignment in bytes. It can be: \c #Aligned128, , \c #Aligned64, \c #Aligned32, \c #Aligned16, \c #Aligned8 or \c #Unaligned. + * The default is \c #Unaligned. + * \tparam StrideType optionally specifies strides. By default, Ref implies a contiguous storage along the inner dimension (inner stride==1), + * but accepts a variable outer stride (leading dimension). + * This can be overridden by specifying strides. + * The type passed here must be a specialization of the Stride template, see examples below. + * + * This class provides a way to write non-template functions taking Eigen objects as parameters while limiting the number of copies. + * A Ref<> object can represent either a const expression or a l-value: + * \code + * // in-out argument: + * void foo1(Ref x); + * + * // read-only const argument: + * void foo2(const Ref& x); + * \endcode + * + * In the in-out case, the input argument must satisfy the constraints of the actual Ref<> type, otherwise a compilation issue will be triggered. + * By default, a Ref can reference any dense vector expression of float having a contiguous memory layout. + * Likewise, a Ref can reference any column-major dense matrix expression of float whose column's elements are contiguously stored with + * the possibility to have a constant space in-between each column, i.e. the inner stride must be equal to 1, but the outer stride (or leading dimension) + * can be greater than the number of rows. + * + * In the const case, if the input expression does not match the above requirement, then it is evaluated into a temporary before being passed to the function. + * Here are some examples: + * \code + * MatrixXf A; + * VectorXf a; + * foo1(a.head()); // OK + * foo1(A.col()); // OK + * foo1(A.row()); // Compilation error because here innerstride!=1 + * foo2(A.row()); // Compilation error because A.row() is a 1xN object while foo2 is expecting a Nx1 object + * foo2(A.row().transpose()); // The row is copied into a contiguous temporary + * foo2(2*a); // The expression is evaluated into a temporary + * foo2(A.col().segment(2,4)); // No temporary + * \endcode + * + * The range of inputs that can be referenced without temporary can be enlarged using the last two template parameters. + * Here is an example accepting an innerstride!=1: + * \code + * // in-out argument: + * void foo3(Ref > x); + * foo3(A.row()); // OK + * \endcode + * The downside here is that the function foo3 might be significantly slower than foo1 because it won't be able to exploit vectorization, and will involve more + * expensive address computations even if the input is contiguously stored in memory. To overcome this issue, one might propose to overload internally calling a + * template function, e.g.: + * \code + * // in the .h: + * void foo(const Ref& A); + * void foo(const Ref >& A); + * + * // in the .cpp: + * template void foo_impl(const TypeOfA& A) { + * ... // crazy code goes here + * } + * void foo(const Ref& A) { foo_impl(A); } + * void foo(const Ref >& A) { foo_impl(A); } + * \endcode + * + * + * \sa PlainObjectBase::Map(), \ref TopicStorageOrders + */ template class Ref : public RefBase > { private: typedef internal::traits Traits; template - inline Ref(const PlainObjectBase& expr, - typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0); + EIGEN_DEVICE_FUNC inline Ref(const PlainObjectBase& expr, + typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0); public: typedef RefBase Base; @@ -201,23 +205,24 @@ template class Ref #ifndef EIGEN_PARSED_BY_DOXYGEN template - inline Ref(PlainObjectBase& expr, - typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) + EIGEN_DEVICE_FUNC inline Ref(PlainObjectBase& expr, + typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) { - EIGEN_STATIC_ASSERT(static_cast(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + EIGEN_STATIC_ASSERT(bool(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); Base::construct(expr.derived()); } template - inline Ref(const DenseBase& expr, - typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) + EIGEN_DEVICE_FUNC inline Ref(const DenseBase& expr, + typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) #else + /** Implicit constructor from any dense expression */ template inline Ref(DenseBase& expr) #endif { - EIGEN_STATIC_ASSERT(static_cast(internal::is_lvalue::value), THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); - EIGEN_STATIC_ASSERT(static_cast(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); - enum { THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY = Derived::ThisConstantIsPrivateInPlainObjectBase}; + EIGEN_STATIC_ASSERT(bool(internal::is_lvalue::value), THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); + EIGEN_STATIC_ASSERT(bool(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + EIGEN_STATIC_ASSERT(!Derived::IsPlainObjectBase,THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); Base::construct(expr.const_cast_derived()); } @@ -236,36 +241,36 @@ template class Ref< EIGEN_DENSE_PUBLIC_INTERFACE(Ref) template - inline Ref(const DenseBase& expr, - typename internal::enable_if::ScalarTypeMatch),Derived>::type* = 0) + EIGEN_DEVICE_FUNC inline Ref(const DenseBase& expr, + typename internal::enable_if::ScalarTypeMatch),Derived>::type* = 0) { // std::cout << match_helper::HasDirectAccess << "," << match_helper::OuterStrideMatch << "," << match_helper::InnerStrideMatch << "\n"; // std::cout << int(StrideType::OuterStrideAtCompileTime) << " - " << int(Derived::OuterStrideAtCompileTime) << "\n"; // std::cout << int(StrideType::InnerStrideAtCompileTime) << " - " << int(Derived::InnerStrideAtCompileTime) << "\n"; construct(expr.derived(), typename Traits::template match::type()); } - - inline Ref(const Ref& other) : Base(other) { + + EIGEN_DEVICE_FUNC inline Ref(const Ref& other) : Base(other) { // copy constructor shall not copy the m_object, to avoid unnecessary malloc and copy } template - inline Ref(const RefBase& other) { + EIGEN_DEVICE_FUNC inline Ref(const RefBase& other) { construct(other.derived(), typename Traits::template match::type()); } protected: template - void construct(const Expression& expr,internal::true_type) + EIGEN_DEVICE_FUNC void construct(const Expression& expr,internal::true_type) { Base::construct(expr); } template - void construct(const Expression& expr, internal::false_type) + EIGEN_DEVICE_FUNC void construct(const Expression& expr, internal::false_type) { - m_object.lazyAssign(expr); + internal::call_assignment_no_alias(m_object,expr,internal::assign_op()); Base::construct(m_object); } diff --git a/splinter/src/Core/Replicate.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Replicate.h similarity index 66% rename from splinter/src/Core/Replicate.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/Replicate.h index ac4537c142..9960ef884e 100644 --- a/splinter/src/Core/Replicate.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Replicate.h @@ -12,21 +12,6 @@ namespace Eigen { -/** - * \class Replicate - * \ingroup Core_Module - * - * \brief Expression of the multiple replication of a matrix or vector - * - * \param MatrixType the type of the object we are replicating - * - * This class represents an expression of the multiple replication of a matrix or vector. - * It is the return type of DenseBase::replicate() and most of the time - * this is the only way it is used. - * - * \sa DenseBase::replicate() - */ - namespace internal { template struct traits > @@ -35,10 +20,7 @@ struct traits > typedef typename MatrixType::Scalar Scalar; typedef typename traits::StorageKind StorageKind; typedef typename traits::XprKind XprKind; - enum { - Factor = (RowFactor==Dynamic || ColFactor==Dynamic) ? Dynamic : RowFactor*ColFactor - }; - typedef typename nested::type MatrixTypeNested; + typedef typename ref_selector::type MatrixTypeNested; typedef typename remove_reference::type _MatrixTypeNested; enum { RowsAtCompileTime = RowFactor==Dynamic || int(MatrixType::RowsAtCompileTime)==Dynamic @@ -53,12 +35,29 @@ struct traits > IsRowMajor = MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1 ? 1 : MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1 ? 0 : (MatrixType::Flags & RowMajorBit) ? 1 : 0, - Flags = (_MatrixTypeNested::Flags & HereditaryBits & ~RowMajorBit) | (IsRowMajor ? RowMajorBit : 0), - CoeffReadCost = _MatrixTypeNested::CoeffReadCost + + // FIXME enable DirectAccess with negative strides? + Flags = IsRowMajor ? RowMajorBit : 0 }; }; } +/** + * \class Replicate + * \ingroup Core_Module + * + * \brief Expression of the multiple replication of a matrix or vector + * + * \tparam MatrixType the type of the object we are replicating + * \tparam RowFactor number of repetitions at compile time along the vertical direction, can be Dynamic. + * \tparam ColFactor number of repetitions at compile time along the horizontal direction, can be Dynamic. + * + * This class represents an expression of the multiple replication of a matrix or vector. + * It is the return type of DenseBase::replicate() and most of the time + * this is the only way it is used. + * + * \sa DenseBase::replicate() + */ template class Replicate : public internal::dense_xpr_base< Replicate >::type { @@ -68,10 +67,12 @@ template class Replicate typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Replicate) + typedef typename internal::remove_all::type NestedExpression; template - inline explicit Replicate(const OriginalMatrixType& a_matrix) - : m_matrix(a_matrix), m_rowFactor(RowFactor), m_colFactor(ColFactor) + EIGEN_DEVICE_FUNC + inline explicit Replicate(const OriginalMatrixType& matrix) + : m_matrix(matrix), m_rowFactor(RowFactor), m_colFactor(ColFactor) { EIGEN_STATIC_ASSERT((internal::is_same::type,OriginalMatrixType>::value), THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) @@ -79,41 +80,20 @@ template class Replicate } template - inline Replicate(const OriginalMatrixType& a_matrix, Index rowFactor, Index colFactor) - : m_matrix(a_matrix), m_rowFactor(rowFactor), m_colFactor(colFactor) + EIGEN_DEVICE_FUNC + 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), THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows() * m_rowFactor.value(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols() * m_colFactor.value(); } - inline Scalar coeff(Index rowId, Index colId) const - { - // try to avoid using modulo; this is a pure optimization strategy - const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 - : RowFactor==1 ? rowId - : rowId%m_matrix.rows(); - const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 - : ColFactor==1 ? colId - : colId%m_matrix.cols(); - - return m_matrix.coeff(actual_row, actual_col); - } - template - inline PacketScalar packet(Index rowId, Index colId) const - { - const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 - : RowFactor==1 ? rowId - : rowId%m_matrix.rows(); - const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 - : ColFactor==1 ? colId - : colId%m_matrix.cols(); - - return m_matrix.template packet(actual_row, actual_col); - } - + EIGEN_DEVICE_FUNC const _MatrixTypeNested& nestedExpression() const { return m_matrix; @@ -141,21 +121,6 @@ DenseBase::replicate() const return Replicate(derived()); } -/** - * \return an expression of the replication of \c *this - * - * Example: \include MatrixBase_replicate_int_int.cpp - * Output: \verbinclude MatrixBase_replicate_int_int.out - * - * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate - */ -template -const typename DenseBase::ReplicateReturnType -DenseBase::replicate(Index rowFactor,Index colFactor) const -{ - return Replicate(derived(),rowFactor,colFactor); -} - /** * \return an expression of the replication of each column (or row) of \c *this * diff --git a/splinter/src/Core/ReturnByValue.h b/splinter/thirdparty/Eigen/Eigen/src/Core/ReturnByValue.h similarity index 69% rename from splinter/src/Core/ReturnByValue.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/ReturnByValue.h index f635598dcc..c44b7673bb 100644 --- a/splinter/src/Core/ReturnByValue.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/ReturnByValue.h @@ -13,11 +13,6 @@ namespace Eigen { -/** \class ReturnByValue - * \ingroup Core_Module - * - */ - namespace internal { template @@ -38,17 +33,22 @@ struct traits > * So internal::nested always gives the plain return matrix type. * * FIXME: I don't understand why we need this specialization: isn't this taken care of by the EvalBeforeNestingBit ?? + * Answer: EvalBeforeNestingBit should be deprecated since we have the evaluators */ template -struct nested, n, PlainObject> +struct nested_eval, n, PlainObject> { typedef typename traits::ReturnType type; }; } // end namespace internal +/** \class ReturnByValue + * \ingroup Core_Module + * + */ template class ReturnByValue - : internal::no_assignment_operator, public internal::dense_xpr_base< ReturnByValue >::type + : public internal::dense_xpr_base< ReturnByValue >::type, internal::no_assignment_operator { public: typedef typename internal::traits::ReturnType ReturnType; @@ -57,10 +57,11 @@ template class ReturnByValue EIGEN_DENSE_PUBLIC_INTERFACE(ReturnByValue) template + EIGEN_DEVICE_FUNC inline void evalTo(Dest& dst) const { static_cast(this)->evalTo(dst); } - inline Index rows() const { return static_cast(this)->rows(); } - inline Index cols() const { return static_cast(this)->cols(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return static_cast(this)->rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return static_cast(this)->cols(); } #ifndef EIGEN_PARSED_BY_DOXYGEN #define Unusable YOU_ARE_TRYING_TO_ACCESS_A_SINGLE_COEFFICIENT_IN_A_SPECIAL_EXPRESSION_WHERE_THAT_IS_NOT_ALLOWED_BECAUSE_THAT_WOULD_BE_INEFFICIENT @@ -72,8 +73,7 @@ template class ReturnByValue const Unusable& coeff(Index,Index) const { return *reinterpret_cast(this); } Unusable& coeffRef(Index) { return *reinterpret_cast(this); } Unusable& coeffRef(Index,Index) { return *reinterpret_cast(this); } - template Unusable& packet(Index) const; - template Unusable& packet(Index, Index) const; +#undef Unusable #endif }; @@ -85,14 +85,32 @@ Derived& DenseBase::operator=(const ReturnByValue& other) return derived(); } +namespace internal { + +// Expression is evaluated in a temporary; default implementation of Assignment is bypassed so that +// when a ReturnByValue expression is assigned, the evaluator is not constructed. +// TODO: Finalize port to new regime; ReturnByValue should not exist in the expression world + template -template -Derived& DenseBase::lazyAssign(const ReturnByValue& other) +struct evaluator > + : public evaluator::ReturnType> { - other.evalTo(derived()); - return derived(); -} + typedef ReturnByValue XprType; + typedef typename internal::traits::ReturnType PlainObject; + typedef evaluator Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + xpr.evalTo(m_result); + } + +protected: + PlainObject m_result; +}; +} // end namespace internal } // end namespace Eigen diff --git a/splinter/thirdparty/Eigen/Eigen/src/Core/Reverse.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Reverse.h new file mode 100644 index 0000000000..0640cda2a1 --- /dev/null +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Reverse.h @@ -0,0 +1,211 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2009 Ricard Marxer +// Copyright (C) 2009-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_REVERSE_H +#define EIGEN_REVERSE_H + +namespace Eigen { + +namespace internal { + +template +struct traits > + : traits +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename traits::StorageKind StorageKind; + typedef typename traits::XprKind XprKind; + typedef typename ref_selector::type MatrixTypeNested; + typedef typename remove_reference::type _MatrixTypeNested; + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime, + MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, + Flags = _MatrixTypeNested::Flags & (RowMajorBit | LvalueBit) + }; +}; + +template struct reverse_packet_cond +{ + static inline PacketType run(const PacketType& x) { return preverse(x); } +}; + +template struct reverse_packet_cond +{ + static inline PacketType run(const PacketType& x) { return x; } +}; + +} // end namespace internal + +/** \class Reverse + * \ingroup Core_Module + * + * \brief Expression of the reverse of a vector or matrix + * + * \tparam MatrixType the type of the object of which we are taking the reverse + * \tparam Direction defines the direction of the reverse operation, can be Vertical, Horizontal, or BothDirections + * + * This class represents an expression of the reverse of a vector. + * It is the return type of MatrixBase::reverse() and VectorwiseOp::reverse() + * and most of the time this is the only way it is used. + * + * \sa MatrixBase::reverse(), VectorwiseOp::reverse() + */ +template class Reverse + : public internal::dense_xpr_base< Reverse >::type +{ + public: + + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Reverse) + typedef typename internal::remove_all::type NestedExpression; + using Base::IsRowMajor; + + protected: + enum { + PacketSize = internal::packet_traits::size, + IsColMajor = !IsRowMajor, + ReverseRow = (Direction == Vertical) || (Direction == BothDirections), + ReverseCol = (Direction == Horizontal) || (Direction == BothDirections), + OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, + OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1, + ReversePacket = (Direction == BothDirections) + || ((Direction == Vertical) && IsColMajor) + || ((Direction == Horizontal) && IsRowMajor) + }; + typedef internal::reverse_packet_cond reverse_packet; + public: + + EIGEN_DEVICE_FUNC explicit inline Reverse(const MatrixType& matrix) : m_matrix(matrix) { } + + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Reverse) + + EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols(); } + + EIGEN_DEVICE_FUNC inline Index innerStride() const + { + return -m_matrix.innerStride(); + } + + EIGEN_DEVICE_FUNC const typename internal::remove_all::type& + nestedExpression() const + { + return m_matrix; + } + + protected: + typename MatrixType::Nested m_matrix; +}; + +/** \returns an expression of the reverse of *this. + * + * Example: \include MatrixBase_reverse.cpp + * Output: \verbinclude MatrixBase_reverse.out + * + */ +template +inline typename DenseBase::ReverseReturnType +DenseBase::reverse() +{ + return ReverseReturnType(derived()); +} + + +//reverse const overload moved DenseBase.h due to a CUDA compiler bug + +/** This is the "in place" version of reverse: it reverses \c *this. + * + * In most cases it is probably better to simply use the reversed expression + * of a matrix. However, when reversing the matrix data itself is really needed, + * then this "in-place" version is probably the right choice because it provides + * the following additional benefits: + * - less error prone: doing the same operation with .reverse() requires special care: + * \code m = m.reverse().eval(); \endcode + * - this API enables reverse operations without the need for a temporary + * - it allows future optimizations (cache friendliness, etc.) + * + * \sa VectorwiseOp::reverseInPlace(), reverse() */ +template +inline void DenseBase::reverseInPlace() +{ + if(cols()>rows()) + { + Index half = cols()/2; + leftCols(half).swap(rightCols(half).reverse()); + if((cols()%2)==1) + { + Index half2 = rows()/2; + col(half).head(half2).swap(col(half).tail(half2).reverse()); + } + } + else + { + Index half = rows()/2; + topRows(half).swap(bottomRows(half).reverse()); + if((rows()%2)==1) + { + Index half2 = cols()/2; + row(half).head(half2).swap(row(half).tail(half2).reverse()); + } + } +} + +namespace internal { + +template +struct vectorwise_reverse_inplace_impl; + +template<> +struct vectorwise_reverse_inplace_impl +{ + template + static void run(ExpressionType &xpr) + { + Index half = xpr.rows()/2; + xpr.topRows(half).swap(xpr.bottomRows(half).colwise().reverse()); + } +}; + +template<> +struct vectorwise_reverse_inplace_impl +{ + template + static void run(ExpressionType &xpr) + { + Index half = xpr.cols()/2; + xpr.leftCols(half).swap(xpr.rightCols(half).rowwise().reverse()); + } +}; + +} // end namespace internal + +/** This is the "in place" version of VectorwiseOp::reverse: it reverses each column or row of \c *this. + * + * In most cases it is probably better to simply use the reversed expression + * of a matrix. However, when reversing the matrix data itself is really needed, + * then this "in-place" version is probably the right choice because it provides + * the following additional benefits: + * - less error prone: doing the same operation with .reverse() requires special care: + * \code m = m.reverse().eval(); \endcode + * - this API enables reverse operations without the need for a temporary + * + * \sa DenseBase::reverseInPlace(), reverse() */ +template +void VectorwiseOp::reverseInPlace() +{ + internal::vectorwise_reverse_inplace_impl::run(_expression().const_cast_derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_REVERSE_H diff --git a/splinter/src/Core/Select.h b/splinter/thirdparty/Eigen/Eigen/src/Core/Select.h similarity index 88% rename from splinter/src/Core/Select.h rename to splinter/thirdparty/Eigen/Eigen/src/Core/Select.h index 87993bbb55..79eec1b5b0 100644 --- a/splinter/src/Core/Select.h +++ b/splinter/thirdparty/Eigen/Eigen/src/Core/Select.h @@ -43,23 +43,21 @@ struct traits > ColsAtCompileTime = ConditionMatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = ConditionMatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = ConditionMatrixType::MaxColsAtCompileTime, - Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & HereditaryBits, - CoeffReadCost = traits::type>::CoeffReadCost - + EIGEN_SIZE_MAX(traits::type>::CoeffReadCost, - traits::type>::CoeffReadCost) + Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & RowMajorBit }; }; } template -class Select : internal::no_assignment_operator, - public internal::dense_xpr_base< Select >::type +class Select : public internal::dense_xpr_base< Select >::type, + internal::no_assignment_operator { public: typedef typename internal::dense_xpr_base